dio_retry_it 8.0.1 copy "dio_retry_it: ^8.0.1" to clipboard
dio_retry_it: ^8.0.1 copied to clipboard

Retry library for Dio and Dio package made with love. By default, the request will be retried only for appropriate retryable http statuses.

Dio Retry It ๐Ÿš€ #

A Smarter retry interceptor for Dio with exponential backoff and full jitter based on dio_smart_retry

Pub Version Dart SDK Version style: very good analysis License

โœจ Why Dio Retry It? #

When building production apps, network failures are inevitable. Dio Retry It automatically handles these failures with an intelligent retry strategy that protects your servers from traffic spikes and improves user experience.

๐ŸŽฏ Key Features #

  • โšก Smart Retry Logic - Automatically retries failed requests based on configurable rules
  • ๐Ÿ“ˆ Exponential Backoff with Full Jitter - Prevents thundering herd problems when servers recover
  • ๐ŸŽฒ Random Delays - Avoids synchronized retry storms from thousands of clients
  • ๐Ÿ”„ FormData Support - Automatically clones FormData before retrying
  • ๐Ÿšซ Per-Request Control - Disable retries for specific requests when needed
  • ๐Ÿ“ Built-in Logging - Track retry attempts with custom log functions
  • ๐Ÿ”’ Null Safety - Fully migrated to sound null safety
  • โš™๏ธ Highly Configurable - Customize every aspect of the retry behavior

๐Ÿ“‘ Table of Contents #

๐Ÿš€ Getting Started #

Installation #

Add to your pubspec.yaml:

dependencies:
  dio_retry_it: ^8.0.1

Then import it:

import 'package:dio_retry_it/dio_retry_it.dart';

Basic Usage #

final dio = Dio();

// Add the retry interceptor
dio.interceptors.add(
  RetryInterceptor(
    dio: dio,
    maxAttempts: 3,              // Retry up to 3 times
    baseDelay: Duration(milliseconds: 500),  // Start with 500ms
    maxDelay: Duration(seconds: 10),         // Cap at 10 seconds
    backoffFactor: 2.0,          // Double the delay each attempt
    logPrint: print,             // Optional: log retry attempts
  ),
);

// Now every failed request will be automatically retried
try {
  await dio.get('https://api.example.com/data');
} catch (e) {
  // After all retries fail, the error will be thrown
  print('Request failed after retries: $e');
}

๐ŸŽฏ How It Works #

The Retry Strategy #

Unlike simple fixed-delay retries, Dio Retry It uses exponential backoff with full jitter - the gold standard for distributed systems.

The Algorithm:

  1. Calculate exponential delay: baseDelay ร— backoffFactor^(attempt-1)
  2. Cap at maxDelay
  3. Apply full jitter: pick a random delay between 0 and the capped value

Example with defaults (baseDelay: 500ms, backoffFactor: 2.0, maxDelay: 10s):

Attempt Calculation Delay Range
1 500ms ร— 2โฐ 0-500ms
2 500ms ร— 2ยน 0-1,000ms
3 500ms ร— 2ยฒ 0-2,000ms
4 500ms ร— 2ยณ 0-4,000ms
5 500ms ร— 2โด 0-8,000ms
6+ Capped at 10s 0-10,000ms

๐Ÿ›ก๏ธ Why Full Jitter Matters #

Imagine thousands of clients all hitting a server that's temporarily down. When the server recovers, without jitter, all clients would retry at the exact same moment, causing a massive traffic spike - effectively a DDoS attack on your own servers!

Full jitter solves this by randomizing retry times, spreading the load evenly across the recovery window.

Key Insight: Random jitter matters far more for real-world reliability than a fixed delay schedule. This is why major cloud providers like AWS and Google Cloud recommend jitter-based retries.

๐Ÿ“– Advanced Usage #

Custom Retry Logic #

Sometimes you need finer control over what gets retried:

final dio = Dio();

dio.interceptors.add(
  RetryInterceptor(
    dio: dio,
    maxAttempts: 5,
    retryEvaluator: (error, attempt) async {
      // Only retry specific errors
      if (error.type == DioExceptionType.connectionTimeout) return true;
      if (error.type == DioExceptionType.receiveTimeout) return true;
      
      // Retry server errors but not client errors
      if (error.type == DioExceptionType.badResponse) {
        final status = error.response?.statusCode ?? 0;
        return status >= 500 && status < 600;
      }
      
      return false;
    },
  ),
);

Custom Retry Delays #

Configure retry behavior for your specific needs:

dio.interceptors.add(
  RetryInterceptor(
    dio: dio,
    maxAttempts: 5,
    baseDelay: Duration(seconds: 1),     // Start with 1 second
    maxDelay: Duration(minutes: 1),      // Cap at 1 minute
    backoffFactor: 1.5,                  // Slower growth
    logPrint: (msg) => debugPrint(msg),
  ),
);

Disable Retry for Specific Requests #

Some requests shouldn't be retried (e.g., idempotent operations):

// Using RequestOptions
final request = RequestOptions(path: '/user/delete/123')
  ..disableRetry = true;
await dio.fetch(request);

// Using Options
final response = await dio.get(
  'https://api.example.com/status',
  options: Options(extra: {'disableRetry': true}),
);

Working with FormData #

Dio Retry It automatically clones FormData before retrying - no extra work needed!

final formData = FormData.fromMap({
  'file': await MultipartFile.fromFile('image.jpg'),
  'name': 'My Image',
});

// This will retry automatically if it fails
final response = await dio.post(
  'https://api.example.com/upload',
  data: formData,
);

โš™๏ธ Configuration Reference #

Constructor Parameters #

Parameter Type Default Description
dio Dio Required The Dio instance used for retries
maxAttempts int 3 Maximum retry attempts (excludes original)
baseDelay Duration 500ms Starting delay before backoff
maxDelay Duration 10s Maximum delay cap
backoffFactor double 2.0 Multiplier per attempt (must be โ‰ฅ1)
retryEvaluator RetryEvaluator? Default evaluator Custom retry decision logic
logPrint Function(String)? null Logging callback

Default Retry Status Codes #

By default, responses with these status codes are retried:

  • 408 - Request Timeout
  • 429 - Too Many Requests
  • 500 - Internal Server Error
  • 502 - Bad Gateway
  • 503 - Service Unavailable
  • 504 - Gateway Timeout
  • 440 - Login Timeout (IIS)
  • 460 - Client Closed Request (AWS ELB)
  • 499 - Client Closed Request (nginx)
  • 520 - Web Server Unknown Error
  • 521 - Web Server Is Down
  • 522 - Connection Timed Out
  • 523 - Origin Unreachable
  • 524 - Timeout Occurred
  • 525 - SSL Handshake Failed
  • 527 - Railgun Error
  • 598 - Network Read Timeout
  • 599 - Network Connect Timeout

Extending Status Codes #

// Add your own status codes
final evaluator = DefaultRetryEvaluator(
  {...defaultRetryableStatuses, 401, 403},
);

dio.interceptors.add(
  RetryInterceptor(
    dio: dio,
    retryEvaluator: evaluator.evaluate,
  ),
);

๐Ÿ”„ Migration Guide #

From dio_smart_retry to dio_retry_it #

Key Changes #

dio_smart_retry dio_retry_it
retries: 3 maxAttempts: 3
retryDelays: [...] baseDelay + backoffFactor + maxDelay
retryableExtraStatuses Custom retryEvaluator
Fixed delays Exponential backoff with full jitter โœ…

Migration Examples #

Basic Retry

Before:

RetryInterceptor(
  dio: dio,
  retries: 3,
  retryDelays: const [
    Duration(seconds: 1),
    Duration(seconds: 3),
    Duration(seconds: 5),
  ],
)

After:

RetryInterceptor(
  dio: dio,
  maxAttempts: 3,
  baseDelay: Duration(seconds: 1),
  maxDelay: Duration(seconds: 10),
  backoffFactor: 2.0,
)

Custom Status Codes

Before:

RetryInterceptor(
  dio: dio,
  retries: 3,
  retryableExtraStatuses: {401, 403},
)

After:

RetryInterceptor(
  dio: dio,
  maxAttempts: 3,
  retryEvaluator: (error, attempt) {
    if (error.type == DioExceptionType.badResponse) {
      final status = error.response?.statusCode;
      return status == 401 || status == 403;
    }
    return false;
  },
)

Removed Parameters #

Parameter Replacement
retryableExtraStatuses Custom retryEvaluator
ignoreRetryEvaluatorExceptions Built-in error handling
retryDelays baseDelay + backoffFactor

โœ… Migration Checklist #

  • โŒ Replace retries โ†’ maxAttempts
  • โŒ Replace retryDelays โ†’ baseDelay + backoffFactor
  • โŒ Add maxDelay parameter
  • โŒ Update custom status codes to use retryEvaluator
  • โŒ Remove ignoreRetryEvaluatorExceptions if used
  • โŒ Test your app

Benefit: New package prevents thundering herd problems with exponential backoff + full jitter - critical for production apps with many concurrent users! ๐Ÿš€

๐Ÿ“Š Performance & Best Practices #

๐ŸŽฏ When to Use Retries #

โœ… Good Candidates:

  • GET requests (idempotent)
  • Network timeouts
  • Temporary server errors (5xx)
  • Rate limiting (429)
  • Connection issues

โŒ Avoid Retries For:

  • POST/PUT/DELETE mutations (unless idempotent)
  • Client errors (4xx except 429)
  • Cancelled requests
  • Format/serialization errors

๐Ÿ“ˆ Production Recommendations #

// Recommended production configuration
dio.interceptors.add(
  RetryInterceptor(
    dio: dio,
    maxAttempts: 3,
    baseDelay: Duration(milliseconds: 1000),
    maxDelay: Duration(seconds: 30),
    backoffFactor: 2.0,
    logPrint: (msg) {
      // Only log in development
      if (kDebugMode) print(msg);
    },
  ),
);

๐Ÿค Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

๐Ÿ“„ License #

Distributed under the MIT License. See LICENSE for more information.

๐Ÿ™ Acknowledgments #

This package is a next-generation fork of the abandoned dio_smart_retry package, rebuilt with:

  • โœ… Modern Dart practices
  • โœ… Full null safety
  • โœ… Exponential backoff with full jitter
  • โœ… Better FormData handling
  • โœ… Improved error handling
  • โœ… Better test coverage

๐Ÿ“ž Support #


Made with โค๏ธ for the Dart community


ยฉ 2026 Silify

1
likes
160
points
192
downloads

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

Retry library for Dio and Dio package made with love. By default, the request will be retried only for appropriate retryable http statuses.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

dio, http_parser, path

More

Packages that depend on dio_retry_it