Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RetryInterceptor's exception cannot be catched by future's catchError #1894

Closed
allen218 opened this issue Jul 12, 2023 · 2 comments
Closed
Labels
i: wontfix This will not be worked on

Comments

@allen218
Copy link

allen218 commented Jul 12, 2023

Package

dio

Version

5.2.0+1

Output of flutter doctor -v

[√] Flutter (Channel stable, 3.10.2, on Microsoft Windows [Version 10.0.19045.2006], locale zh-CN)
    • Flutter version 3.10.2 on channel stable at F:\Android_Related\Android_ALL\flutter          
    • Upstream repository https://github.com/flutter/flutter.git                                  
    • Framework revision 9cd3d0d9ff (7 weeks ago), 2023-05-23 20:57:28 -0700
    • Engine revision 90fa3ae28f
    • Dart version 3.0.2
    • DevTools version 2.23.1

[√] Windows Version (Installed version of Windows is version 10 or higher)

[√] Android Studio (version 2022.2)
    • Android Studio at F:\Android_Related\Android_ALL\android-studio
    • Flutter plugin can be installed from:
       https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
       https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-b2043.56-9586694)

[√] Android Studio (version 2022.3)
    • Android Studio at F:\Android_Related\android-studio
    • Flutter plugin can be installed from:
       https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
       https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-b2043.56-9884540)

Dart Version

3.0.2

Steps to Reproduce

class RetryInterceptor extends Interceptor {
  final ApiClient apiClient;

  RetryInterceptor({required this.apiClient});

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) async {
    LoginUtils().e("onError", err);

    var retryCount = err.requestOptions.extra["retry_count"] ?? 0;
    err.requestOptions.extra["retry_count"] = retryCount + 1;

    if (isConnectionTimeout(err) && retryCount <= Net.RETRY_MAX_COUNT) {
      // connection timeout retry
      var requestOptions = err.requestOptions;
      Options options = Options(
        method: requestOptions.method,
        sendTimeout: requestOptions.sendTimeout,
        receiveTimeout: requestOptions.receiveTimeout,
        extra: requestOptions.extra,
        headers: requestOptions.headers,
        responseType: requestOptions.responseType,
        contentType: requestOptions.contentType,
        validateStatus: requestOptions.validateStatus,
        receiveDataWhenStatusError: requestOptions.receiveDataWhenStatusError,
        followRedirects: requestOptions.followRedirects,
        maxRedirects: requestOptions.maxRedirects,
        requestEncoder: requestOptions.requestEncoder,
        responseDecoder: requestOptions.responseDecoder,
        listFormat: requestOptions.listFormat,
      );

      sleep(const Duration(seconds: 1));
      var response = await apiClient.dio.request(
        requestOptions.path,
        cancelToken: requestOptions.cancelToken,
        data: requestOptions.data,
        onReceiveProgress: requestOptions.onReceiveProgress,
        options: options,
        onSendProgress: requestOptions.onSendProgress,
        queryParameters: requestOptions.queryParameters,
      );

      return handler.resolve(response);
    }


    super.onError(err, handler);
  }
}

Expected Result

it should throw the exception and future's catchError method can catch this when retry count > RETRY_MAX_COUNT.

Actual Result

It throw an unhandled exception below

E/flutter (20738): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: DioException [unknown]: null
E/flutter (20738): Error: SocketException: Failed host lookup: 'xxx.com' (OS Error: No address associated with hostname, errno = 7)
E/flutter (20738): #0      DioMixin.fetch.<anonymous closure> (package:dio/src/dio_mixin.dart:533:7)
E/flutter (20738): #1      _RootZone.runUnary (dart:async/zone.dart:1661:54)
E/flutter (20738): #2      _FutureListener.handleError (dart:async/future_impl.dart:165:22)
E/flutter (20738): #3      Future._propagateToListeners.handleError (dart:async/future_impl.dart:796:47)
E/flutter (20738): #4      Future._propagateToListeners (dart:async/future_impl.dart:817:13)
E/flutter (20738): #5      Future._completeError (dart:async/future_impl.dart:592:5)
E/flutter (20738): #6      _SyncCompleter._completeError (dart:async/future_impl.dart:51:12)
E/flutter (20738): #7      _Completer.completeError (dart:async/future_impl.dart:23:5)
E/flutter (20738): #8      Future.any.onError (dart:async/future.dart:620:45)
E/flutter (20738): #9      _RootZone.runBinary (dart:async/zone.dart:1666:54)
E/flutter (20738): #10     _FutureListener.handleError (dart:async/future_impl.dart:162:22)
E/flutter (20738): #11     Future._propagateToListeners.handleError (dart:async/future_impl.dart:796:47)
E/flutter (20738): #12     Future._propagateToListeners (dart:async/future_impl.dart:817:13)
E/flutter (20738): #13     Future._completeError (dart:async/future_impl.dart:592:5)
E/flutter (20738): #14     Future._asyncCompleteError.<anonymous closure> (dart:async/future_impl.dart:683:7)
E/flutter (20738): #15     _microtaskLoop (dart:async/schedule_microtask.dart:40:21)
E/flutter (20738): #16     _startMicrotaskLoop (dart:async/schedule_microtask.dart:49:5)

not catched by future's catchError method. but it can catch the exception when I comment the RetryInterceptor.

@allen218 allen218 added h: need triage This issue needs to be categorized s: bug Something isn't working labels Jul 12, 2023
@AlexV525 AlexV525 added h: need more info Further information is requested and removed h: need triage This issue needs to be categorized s: bug Something isn't working labels Jul 14, 2023
@AlexV525
Copy link
Member

  • It seems like you're using asynchronized method in onError, please use QueuedInterceptor rather than Interceptor and declare the onError as Future<void> onError(DioException err, ErrorInterceptorHandler handler) async {}.
  • Instead of using super.onError(err, handler), it'll be better to use handler.next(err).

@allen218
Copy link
Author

allen218 commented Jul 18, 2023

  • It seems like you're using asynchronized method in onError, please use QueuedInterceptor rather than Interceptor and declare the onError as Future<void> onError(DioException err, ErrorInterceptorHandler handler) async {}.
  • Instead of using super.onError(err, handler), it'll be better to use handler.next(err).

Thx! This issue has been resolved. Just call future's then method and handle.resolve() to do that, it works. That last code snippet is blow:

class RetryInterceptor extends Interceptor {
  final ApiClient apiClient;

  RetryInterceptor({required this.apiClient});

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) async {
    LoginUtils().e("onError", err);

    var retryCount = err.requestOptions.extra["retry_count"] ?? 0;
    err.requestOptions.extra["retry_count"] = retryCount + 1;

    if (isConnectionTimeout(err) && retryCount <= Net.RETRY_MAX_COUNT) {
      // connection timeout retry
      var requestOptions = err.requestOptions;
      Options options = Options(
        method: requestOptions.method,
        sendTimeout: requestOptions.sendTimeout,
        receiveTimeout: requestOptions.receiveTimeout,
        extra: requestOptions.extra,
        headers: requestOptions.headers,
        responseType: requestOptions.responseType,
        contentType: requestOptions.contentType,
        validateStatus: requestOptions.validateStatus,
        receiveDataWhenStatusError: requestOptions.receiveDataWhenStatusError,
        followRedirects: requestOptions.followRedirects,
        maxRedirects: requestOptions.maxRedirects,
        requestEncoder: requestOptions.requestEncoder,
        responseDecoder: requestOptions.responseDecoder,
        listFormat: requestOptions.listFormat,
      );
      // err.requestOptions

      sleep(const Duration(seconds: 1));
      return await apiClient.dio
          .request(
            requestOptions.path,
            cancelToken: requestOptions.cancelToken,
            data: requestOptions.data,
            onReceiveProgress: requestOptions.onReceiveProgress,
            options: options,
            onSendProgress: requestOptions.onSendProgress,
            queryParameters: requestOptions.queryParameters,
          )
          .then(handler.resolve,
              onError: (error) => handler
                  .reject(err.copyWith(error: NetworkTimeoutException(err))));
    }

    handler.next(err);
  }
}

Hope that method can help others meet the same issue.

@AlexV525 AlexV525 closed this as not planned Won't fix, can't repro, duplicate, stale Jul 19, 2023
@AlexV525 AlexV525 added i: wontfix This will not be worked on and removed h: need more info Further information is requested labels Jul 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
i: wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

2 participants