Retrying
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:
import { Effect } from "effect"
let count = 0
// Simulates an effect with possible failures
export const effect = Effect.async<never, Error, string>((resume) => {
if (count <= 2) {
count++
console.log("failure")
resume(Effect.fail(new Error()))
} else {
console.log("success")
resume(Effect.succeed("yay!"))
}
})
retry
The basic syntax of retry
is as follows:
Effect.retry(effect, policy)
Example
import { Effect, Schedule } from "effect"
import { effect } from "./fake"
// Define a repetition policy using a fixed delay between retries
const policy = Schedule.fixed("100 millis")
const repeated = Effect.retry(effect, policy)
Effect.runPromise(repeated).then(console.log)
/*
Output:
failure
failure
failure
success
yay!
*/
retryN
There is a shortcut when the policy is trivial and the failed effect is immediately retried: retryN(effect)
.
import { Effect } from "effect"
import { effect } from "./fake"
Effect.runPromise(Effect.retryN(effect, 5))
/*
Output:
failure
failure
failure
success
*/
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:
Effect.retryOrElse(effect, policy, fallback)
Example
import { Effect, Schedule, Console } from "effect"
import { effect } from "./fake"
const policy = 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 fail
const repeated = Effect.retryOrElse(effect, policy, () =>
Console.log("orElse").pipe(Effect.as("default value"))
)
Effect.runPromise(repeated).then(console.log)
/*
Output:
failure
failure
failure
orElse
default value
*/