Retrying
On this page
In software development, it's common to encounter situations where an operation may fail temporarily due to various factors such as network issues, resource unavailability, or external dependencies. In such cases, it's often desirable to retry the operation automatically, allowing it to succeed eventually.
Retrying is a powerful mechanism to handle transient failures and ensure the successful execution of critical operations. In Effect retrying is made simple and flexible with built-in functions and scheduling strategies.
In this guide, we will explore the concept of retrying in Effect and learn how to use the retry
and retryOrElse
functions to handle failure scenarios. We'll see how to define retry policies using schedules, which dictate when and how many times the operation should be retried.
Whether you're working on network requests, database interactions, or any other potentially error-prone operations, mastering the retrying capabilities of Effect can significantly enhance the resilience and reliability of your applications.
To demonstrate the functionality of different retry functions, we will be working with the following helper that simulates an effect with possible failures:
ts
import {Effect } from "effect"letcount = 0// Simulates an effect with possible failuresexport consteffect =Effect .async <string,Error >((resume ) => {if (count <= 2) {count ++console .log ("failure")resume (Effect .fail (newError ()))} else {console .log ("success")resume (Effect .succeed ("yay!"))}})
ts
import {Effect } from "effect"letcount = 0// Simulates an effect with possible failuresexport consteffect =Effect .async <string,Error >((resume ) => {if (count <= 2) {count ++console .log ("failure")resume (Effect .fail (newError ()))} else {console .log ("success")resume (Effect .succeed ("yay!"))}})
retry
The basic syntax of retry
is as follows:
ts
Effect.retry(effect, policy)
ts
Effect.retry(effect, policy)
Example
ts
import {Effect ,Schedule } from "effect"import {effect } from "./fake"// Define a repetition policy using a fixed delay between retriesconstpolicy =Schedule .fixed ("100 millis")constrepeated =Effect .retry (effect ,policy )Effect .runPromise (repeated ).then (console .log )/*Output:failurefailurefailuresuccessyay!*/
ts
import {Effect ,Schedule } from "effect"import {effect } from "./fake"// Define a repetition policy using a fixed delay between retriesconstpolicy =Schedule .fixed ("100 millis")constrepeated =Effect .retry (effect ,policy )Effect .runPromise (repeated ).then (console .log )/*Output:failurefailurefailuresuccessyay!*/
retry n times
There is a shortcut when the policy is trivial and the failed effect is immediately retried:
ts
import {Effect } from "effect"import {effect } from "./fake"Effect .runPromise (Effect .retry (effect , {times : 5 }))/*Output:failurefailurefailuresuccess*/
ts
import {Effect } from "effect"import {effect } from "./fake"Effect .runPromise (Effect .retry (effect , {times : 5 }))/*Output:failurefailurefailuresuccess*/
retryOrElse
There is another version of retry
that allows us to define a fallback strategy in case of errors.
If something goes wrong, we can handle it using the retryOrElse
function.
It lets us add an orElse
callback that will run when the repetition fails.
The basic syntax of retryOrElse
is as follows:
ts
Effect.retryOrElse(effect, policy, fallback)
ts
Effect.retryOrElse(effect, policy, fallback)
Example
ts
import {Effect ,Schedule ,Console } from "effect"import {effect } from "./fake"constpolicy =Schedule .addDelay (Schedule .recurs (2), // Retry for a maximum of 2 times() => "100 millis" // Add a delay of 100 milliseconds between retries)// Create a new effect that retries the effect with the specified policy,// and provides a fallback effect if all retries failconstrepeated =Effect .retryOrElse (effect ,policy , () =>Console .log ("orElse").pipe (Effect .as ("default value")))Effect .runPromise (repeated ).then (console .log )/*Output:failurefailurefailureorElsedefault value*/
ts
import {Effect ,Schedule ,Console } from "effect"import {effect } from "./fake"constpolicy =Schedule .addDelay (Schedule .recurs (2), // Retry for a maximum of 2 times() => "100 millis" // Add a delay of 100 milliseconds between retries)// Create a new effect that retries the effect with the specified policy,// and provides a fallback effect if all retries failconstrepeated =Effect .retryOrElse (effect ,policy , () =>Console .log ("orElse").pipe (Effect .as ("default value")))Effect .runPromise (repeated ).then (console .log )/*Output:failurefailurefailureorElsedefault value*/