From 838b2924569174ba6ae843de741d5eb178db8e2a Mon Sep 17 00:00:00 2001 From: rzuasti Date: Sun, 31 May 2026 17:19:00 -0400 Subject: [PATCH] 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 --- frontend/lib/utils/oott_api.dart | 21 +++++++++++++++++++++ frontend/pubspec.lock | 8 ++++++++ frontend/pubspec.yaml | 1 + 3 files changed, 30 insertions(+) diff --git a/frontend/lib/utils/oott_api.dart b/frontend/lib/utils/oott_api.dart index ecd852f..8625385 100644 --- a/frontend/lib/utils/oott_api.dart +++ b/frontend/lib/utils/oott_api.dart @@ -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()); } diff --git a/frontend/pubspec.lock b/frontend/pubspec.lock index 36754e2..fcce8f7 100644 --- a/frontend/pubspec.lock +++ b/frontend/pubspec.lock @@ -89,6 +89,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.9.1" + dio_smart_retry: + dependency: "direct main" + description: + name: dio_smart_retry + sha256: c8e20da5f49289fa7dce5c9c6b5b120928e3661aefa0fa2d206ea6d93f580928 + url: "https://pub.dev" + source: hosted + version: "7.0.1" dio_web_adapter: dependency: transitive description: diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml index d741398..8e910f0 100644 --- a/frontend/pubspec.yaml +++ b/frontend/pubspec.yaml @@ -13,6 +13,7 @@ dependencies: intl: ^0.20.2 provider: ^6.1.5 dio: ^5.9.1 + dio_smart_retry: ^7.0.1 encrypter: ^2.0.0 shared_preferences: ^2.5.4 fl_chart: ^1.2.0