Repetition

On this page

Repetition is a common requirement when working with effects in software development. It allows us to perform an effect multiple times according to a specific repetition policy.

Repeat policies are used in the following functions:

  • repeat: Repeats an effect until the schedule is done.
  • repeatOrElse: Repeats an effect until the schedule is done, with a fallback for errors.

Scheduled recurrences are in addition to the first execution, so that repeat(effect, Schedule.once) yields an effect that executes effect, and then if that succeeds, executes effect an additional time.

repeat

The basic syntax of repeat is as follows:

ts
Effect.repeat(action, policy)
ts
Effect.repeat(action, policy)

Example

ts
import { Effect, Schedule, Console } from "effect"
 
const action = Console.log("success")
 
const policy = Schedule.addDelay(
Schedule.recurs(2), // Repeat for a maximum of 2 times
() => "100 millis" // Add a delay of 100 milliseconds between repetitions
)
 
const program = Effect.repeat(action, policy)
 
Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`))
/*
Output:
success
success
success
repetitions: 2
*/
ts
import { Effect, Schedule, Console } from "effect"
 
const action = Console.log("success")
 
const policy = Schedule.addDelay(
Schedule.recurs(2), // Repeat for a maximum of 2 times
() => "100 millis" // Add a delay of 100 milliseconds between repetitions
)
 
const program = Effect.repeat(action, policy)
 
Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`))
/*
Output:
success
success
success
repetitions: 2
*/

repeatOrElse

There is another version of repeat that helps us to have a fallback strategy in case of errors. If something goes wrong we can handle that by using the Effect.repeatOrElse function, which helps us to add an orElse callback that will run in case of repetition failure.

The basic syntax of repeatOrElse is as follows:

ts
Effect.repeatOrElse(action, policy, fallback)
ts
Effect.repeatOrElse(action, policy, fallback)

Example

ts
import { Effect, Schedule } from "effect"
 
let count = 0
 
// Define an async effect that simulates an action with possible failures
const action = Effect.async<string, Error>((resume) => {
if (count > 1) {
console.log("failure")
resume(Effect.fail(new Error()))
} else {
count++
console.log("success")
resume(Effect.succeed("yay!"))
}
})
 
const policy = Schedule.addDelay(
Schedule.recurs(2), // Repeat for a maximum of 2 times
() => "100 millis" // Add a delay of 100 milliseconds between repetitions
)
 
const program = Effect.repeatOrElse(action, policy, () =>
Effect.sync(() => {
console.log("orElse")
return count - 1
})
)
 
Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`))
/*
Output:
success
success
failure
orElse
repetitions: 1
*/
ts
import { Effect, Schedule } from "effect"
 
let count = 0
 
// Define an async effect that simulates an action with possible failures
const action = Effect.async<string, Error>((resume) => {
if (count > 1) {
console.log("failure")
resume(Effect.fail(new Error()))
} else {
count++
console.log("success")
resume(Effect.succeed("yay!"))
}
})
 
const policy = Schedule.addDelay(
Schedule.recurs(2), // Repeat for a maximum of 2 times
() => "100 millis" // Add a delay of 100 milliseconds between repetitions
)
 
const program = Effect.repeatOrElse(action, policy, () =>
Effect.sync(() => {
console.log("orElse")
return count - 1
})
)
 
Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`))
/*
Output:
success
success
failure
orElse
repetitions: 1
*/