Add dio_smart_retry for automatic GET request retries

Transient network hiccups and temporary backend errors (5xx, timeouts)
now retry transparently up to twice (1 s then 3 s backoff) before
surfacing an error to the user. Non-idempotent methods (POST, PUT,
DELETE), cancellations, and non-retryable status codes are excluded.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
rzuasti
2026-05-31 17:19:00 -04:00
co-authored by Claude Sonnet 4.6
parent 7437b511ed
commit 838b292456
3 changed files with 30 additions and 0 deletions
+21
View File
@@ -1,6 +1,7 @@
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:dio_smart_retry/dio_smart_retry.dart';
import 'package:encrypter/encrypter/xor.dart';
import 'package:flutter/foundation.dart';
import 'package:frontend/utils/pref_utils.dart';
@@ -16,6 +17,25 @@ const _connectTimeout = Duration(seconds: 5);
const _receiveTimeout = Duration(seconds: 15);
const _sendTimeout = Duration(seconds: 15);
const _retryableStatuses = {408, 429, 500, 502, 503, 504};
RetryInterceptor _buildRetryInterceptor(Dio dio) => RetryInterceptor(
dio: dio,
retries: 2,
retryDelays: const [Duration(seconds: 1), Duration(seconds: 3)],
logPrint: kDebugMode ? (msg) => debugPrint(msg.toString()) : null,
retryEvaluator: (error, attempt) {
if (error.requestOptions.method != 'GET') return false;
if (error.type == DioExceptionType.cancel) return false;
if (error.error is FormatException) return false;
if (error.type == DioExceptionType.badResponse) {
final status = error.response?.statusCode;
return status != null && _retryableStatuses.contains(status);
}
return true;
},
);
LogInterceptor _buildLogInterceptor() => LogInterceptor(
request: true,
requestHeader: false,
@@ -87,6 +107,7 @@ class BackendAPI {
},
),
);
_dio.interceptors.add(_buildRetryInterceptor(_dio));
if (kDebugMode) {
_dio.interceptors.add(_buildLogInterceptor());
}