{"id":22963995,"url":"https://github.com/nidal-bakir/exponential_back_off","last_synced_at":"2026-04-18T14:03:18.403Z","repository":{"id":65818617,"uuid":"600026170","full_name":"Nidal-Bakir/exponential_back_off","owner":"Nidal-Bakir","description":"Implementation of exponential backoff algorithm using pure dart","archived":false,"fork":false,"pushed_at":"2024-07-08T23:42:28.000Z","size":121,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-19T10:35:14.263Z","etag":null,"topics":["connection","dart","exponential-backoff","flutter","package","pubdev"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Nidal-Bakir.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-02-10T12:19:24.000Z","updated_at":"2025-09-12T12:47:43.000Z","dependencies_parsed_at":"2024-07-09T03:46:07.296Z","dependency_job_id":"d61eb84c-3dfb-407d-ad16-d385fe1c76b6","html_url":"https://github.com/Nidal-Bakir/exponential_back_off","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/Nidal-Bakir/exponential_back_off","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nidal-Bakir%2Fexponential_back_off","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nidal-Bakir%2Fexponential_back_off/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nidal-Bakir%2Fexponential_back_off/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nidal-Bakir%2Fexponential_back_off/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Nidal-Bakir","download_url":"https://codeload.github.com/Nidal-Bakir/exponential_back_off/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nidal-Bakir%2Fexponential_back_off/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31971493,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T00:39:45.007Z","status":"online","status_checked_at":"2026-04-18T02:00:07.018Z","response_time":103,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["connection","dart","exponential-backoff","flutter","package","pubdev"],"created_at":"2024-12-14T19:42:54.862Z","updated_at":"2026-04-18T14:03:13.375Z","avatar_url":"https://github.com/Nidal-Bakir.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![exponential_back_off](https://github.com/Nidal-Bakir/exponential_back_off/actions/workflows/exponential_back_off.yml/badge.svg)](https://github.com/Nidal-Bakir/exponential_back_off/actions/workflows/exponential_back_off.yml) [![codecov](https://codecov.io/gh/Nidal-Bakir/exponential_back_off/branch/main/graph/badge.svg?token=WMK1RZQ2JE)](https://codecov.io/gh/Nidal-Bakir/exponential_back_off) [![exponential_back_off on pub.dev](https://img.shields.io/pub/v/exponential_back_off.svg)](https://pub.dev/packages/exponential_back_off)\n\n## Retry failing processes like HTTP requests using an exponential interval between each retry\n\n**Exponential backoff algorithm:**\n\n- An exponential backoff algorithm retries requests exponentially,\n increasing the waiting time between retries up to a maximum backoff time.\n\n\u003cimg width=\"512\" src=\"https://raw.githubusercontent.com/Nidal-Bakir/exponential_back_off/main/digram_image.png\"/\u003e\n\n## Features\n\n- [X] Start process\n- [X] Stop process\n- [X] Reset Process\n- [X] Set max attempts\n- [X] Set max elapsed time\n- [X] Set max delay between retries\n- [X] Conditional retry\n- [X] On retry callback\n- [X] Tweak the exponential delay parameters\n- [X] Specify the amount of randomness for the delays\n- [X] Custom delay algorithm (inherit from the base class `BackOff`)\n\n## Getting started\n\n 1. Add the package to your `pubspec.yaml`\n\n   ```YAML\n   dependencies:\n    exponential_back_off: ^x.y.z\n   ```\n\n2. Import `exponential_back_off` in a dart file.\n\n```dart\nimport 'package:exponential_back_off/exponential_back_off.dart';\n```\n\n## Usage\n\n- Create `ExponentialBackOff` object\n\n```dart\n\nfinal exponentialBackOff = ExponentialBackOff();\n```\n\n- Make a request\n\n```dart\n  final result = await exponentialBackOff.start\u003cResponse\u003e(\n    () =\u003e http.get(Uri.parse('https://www.gnu.org/')),\n  );\n```\n\n- Handle the result\\\n    You can handel the result in two ways:\n  - By checking if the result `isLeft` or `isRight`. and get the value accordingly.\n  - Using the fold function `result.fold((error){},(data){})`. The fold function\n     will call the first(Left) function if the result is error otherwise will call second\n     function(Right) if the result is data.\n\n   *The error will always be in **Left** and the data will always be in **Right***\n\n  1. **Using if check:**\n\n   ```dart\n  result.fold(\n    (error) {\n      //Left(Exception): handel the error\n      print(error);\n    },\n    (response) {\n      //Right(Response): handel the result\n      print(response.body);\n    },\n  );\n  ```\n\n  2. **Using fold:**\n\n   ```dart\n  result.fold(\n    (error) {\n      //Left(Exception): handel the error\n      print(error);\n    },\n    (response) {\n      //Right(Response): handel the result\n      print(response.body);\n    },\n  );\n    ```\n\n#### NOTE\n\nWith the default configuration it will be retried up-to 10 times,\nsleeping 1st, 2nd, 3rd, ..., 9th attempt: (will not sleep the 10th)\n\n      randomPercent: \u003e=0.0% \u003c=15%\n      \n      1.  400 ms     +/- (randomPercent of 400 ms)\n      2.  800 ms     +/- (randomPercent of 800 ms)\n      3.  1600 ms    +/- (randomPercent of 1600 ms)\n      4.  3200 ms    +/- (randomPercent of 3200 ms)\n      5.  6400 ms    +/- (randomPercent of 6400 ms)\n      6.  12800 ms   +/- (randomPercent of 12800 ms)\n      7.  25600 ms   +/- (randomPercent of 25600 ms)\n      8.  51200 ms   +/- (randomPercent of 51200 ms)\n      9.  102400 ms  +/- (randomPercent of 102400 ms)\n      10. 204800 ms  +/- (randomPercent of 204800 ms) **will not sleep it**\n\n## Examples\n\n**Because we love to see examples in the README (:**\n\n- Simple use case with the default configuration:\n\n```dart\n  final exponentialBackOff = ExponentialBackOff();\n\n  /// The result will be of type [Either\u003cException, Response\u003e]\n  final result = await exponentialBackOff.start\u003cResponse\u003e(\n    // Make a request\n    () {\n      return get(Uri.parse('https://www.gnu.org/'))\n          .timeout(Duration(seconds: 10));\n    },\n    // Retry on SocketException or TimeoutException and other then that the process\n    // will stop and return with the error\n    retryIf: (e) =\u003e e is SocketException || e is TimeoutException,\n  );\n\n  /// You can handel the result in two ways\n  /// * By checking if the result `isLeft` or `isRight`. and get the value accordingly.\n  /// * Using the fold function `result.fold((error){},(data){})`. will call the\n  ///   first(Left) function if the result is error otherwise will call second\n  ///   function(Right) if the result is data.\n  ///\n  /// The error will always be in Left and the data will always be in Right\n\n  // using if check\n  if (result.isLeft()) {\n    //Left(Exception): handel the error\n    final error = result.getLeftValue();\n    print(error);\n  } else {\n    //Right(Response): handel the result\n    final response = result.getRightValue();\n    print(response.body);\n  }\n  \n  // using fold:\n  result.fold(\n    (error) {\n      //Left(Exception): handel the error\n      print(error);\n    },\n    (response) {\n      //Right(Response): handel the result\n      print(response.body);\n    },\n  );\n```\n\n- Reusing the same object with the default configuration:\n  \n```dart\n  // reset will call stop() and reset everything to zero\n  await exponentialBackOff.reset();\n\n  print('interval: ' + exponentialBackOff.interval.toString());\n  print('max randomization factor: ' +\n      exponentialBackOff.maxRandomizationFactor.toString());\n  print('max attempts: ' + exponentialBackOff.maxAttempts.toString());\n  print('max delay: ' + exponentialBackOff.maxDelay.toString());\n  print('max elapsed time: ' + exponentialBackOff.maxElapsedTime.toString());\n  print('==================================================================');\n\n await exponentialBackOff.start(\n    () =\u003e get(Uri.parse('https://www.gnu.org/')).timeout(\n       Duration.zero, // it will always throw TimeoutException\n    ),\n    retryIf: (e) =\u003e e is SocketException || e is TimeoutException,\n    onRetry: (error) {\n      print('attempt: ' + exponentialBackOff.attemptCounter.toString());\n      print('error: ' + error.toString());\n      print('current delay: ' + exponentialBackOff.currentDelay.toString());\n      print('elapsed time: ' + exponentialBackOff.elapsedTime.toString());\n      print('--------------------------------------------------------');\n    },\n  );\n```\n\n- Tweaks the exponential delay parameters:\n\n```dart\n  // Will be retried up-to 5 times,\n  // sleeping 1st, 2nd, 3rd, ..., 4th attempt: (will not sleep the 5th)\n  //\n  //   randomPercent: 0.0%\n  //\n  //  1. 200 ms    \n  //  2. 400 ms     \n  //  3. 800 ms    \n  //  4. 1600 ms    \n  //  5. 3200 ms   **will not sleep it**\n \n  final exponentialBackOff = ExponentialBackOff(\n    interval: Duration(milliseconds: 100),\n    maxAttempts: 5,\n    maxRandomizationFactor: 0.0,\n    maxDelay: Duration(seconds: 15),\n  );\n\n  print('interval: ' + exponentialBackOff.interval.toString());\n  print('max randomization factor: ' +\n      exponentialBackOff.maxRandomizationFactor.toString());\n  print('max attempts: ' + exponentialBackOff.maxAttempts.toString());\n  print('max delay: ' + exponentialBackOff.maxDelay.toString());\n  print('max elapsed time: ' + exponentialBackOff.maxElapsedTime.toString());\n  print('==================================================================');\n\n  await exponentialBackOff.start(\n    () =\u003e get(Uri.parse('https://www.gnu.org/')).timeout(\n      Duration.zero, // it will always throw TimeoutException\n    ),\n    retryIf: (e) =\u003e e is SocketException || e is TimeoutException,\n    onRetry: (error) {\n      print('attempt: ' + exponentialBackOff.attemptCounter.toString());\n      print('error: ' + error.toString());\n      print('current delay: ' + exponentialBackOff.currentDelay.toString());\n      print('elapsed time: ' + exponentialBackOff.elapsedTime.toString());\n      print('--------------------------------------------------------');\n    },\n  );\n\n```\n\n- Custom Delay\n  - create a subclass from Backoff base class\n\n      ```dart\n      /// linier delays:\n      ///\n      ///  1. 1000 ms\n      ///  2. 2000 ms\n      ///  3. 3000 ms\n      ///  4. 4000 ms\n      ///  5. 5000 ms\n      class CustomDelay extends BackOff {\n        CustomDelay({\n          super.maxAttempts,\n          super.maxDelay,\n          super.maxElapsedTime,\n        }) : assert(maxAttempts != null || maxElapsedTime != null,\n                  'Can not have both maxAttempts and maxElapsedTime null');\n\n        @override\n        Duration computeDelay(int attempt, Duration elapsedTime) {\n          return Duration(seconds: attempt);\n        }\n      }\n      \n      ```\n\n  - Use it as you normally do\n\n      ```dart\n        // Will be retried up-to 5 times,\n        // sleeping 1st, 2nd, 3rd, ..., 4th attempt: (will not sleep the 5th)\n        //\n        //  1. 1000 ms\n        //  2. 2000 ms\n        //  3. 3000 ms\n        //  4. 4000 ms\n        //  5. 5000 ms   **will not sleep it**\n\n        final customDelay = CustomDelay(maxAttempts: 5);\n\n        print('max attempts: ' + customDelay.maxAttempts.toString());\n        print('max delay: ' + customDelay.maxDelay.toString());\n        print('max elapsed time: ' + customDelay.maxElapsedTime.toString());\n        print('==================================================================');\n\n        await customDelay.start(\n          () =\u003e get(Uri.parse('https://www.gnu.org/')).timeout(\n            Duration.zero, // it will always throw TimeoutException\n          ),\n          retryIf: (e) =\u003e e is SocketException || e is TimeoutException,\n          onRetry: (error) {\n            print('attempt: ' + customDelay.attemptCounter.toString());\n            print('error: ' + error.toString());\n            print('current delay: ' + customDelay.currentDelay.toString());\n            print('elapsed time: ' + customDelay.elapsedTime.toString());\n            print('--------------------------------------------------------');\n          },\n        );\n      ```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnidal-bakir%2Fexponential_back_off","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnidal-bakir%2Fexponential_back_off","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnidal-bakir%2Fexponential_back_off/lists"}