(base: Duration.Input, factor?: number): Schedule<Duration.Duration>Schedule that always recurs, but will wait a certain amount between
repetitions, given by base * factor.pow(n), where n is the number of
repetitions so far. Returns the current duration between recurrences.
Example (Retrying with exponential backoff)
import { Console, Data, Effect, Schedule } from "effect"
class RetryFailure extends Data.TaggedError("RetryFailure")<{ readonly message: string }> {}
// Basic exponential backoff with default factor of 2
const basicExponential = Schedule.exponential("100 millis")
// Delays: 100ms, 200ms, 400ms, 800ms, 1600ms, ...
// Custom exponential backoff with factor 1.5
const gentleExponential = Schedule.exponential("200 millis", 1.5)
// Delays: 200ms, 300ms, 450ms, 675ms, 1012ms, ...
// Retry with exponential backoff (limited to 5 attempts)
const retryPolicy = Schedule.max([
Schedule.exponential("50 millis"),
Schedule.recurs(5)
])
const program = Effect.gen(function*() {
let attempt = 0
const result = yield* Effect.retry(
Effect.gen(function*() {
attempt++
if (attempt < 4) {
yield* Console.log(`Attempt ${attempt} failed, retrying...`)
return yield* Effect.fail(new RetryFailure({ message: `Failure ${attempt}` }))
}
return `Success on attempt ${attempt}`
}),
retryPolicy
)
yield* Console.log(`Final result: ${result}`)
})
// Will retry with delays: 50ms, 100ms, 200ms before successexport const const exponential: (
base: Duration.Input,
factor?: number
) => Schedule<Duration.Duration>
Schedule that always recurs, but will wait a certain amount between
repetitions, given by base * factor.pow(n), where n is the number of
repetitions so far. Returns the current duration between recurrences.
Example (Retrying with exponential backoff)
import { Console, Data, Effect, Schedule } from "effect"
class RetryFailure extends Data.TaggedError("RetryFailure")<{ readonly message: string }> {}
// Basic exponential backoff with default factor of 2
const basicExponential = Schedule.exponential("100 millis")
// Delays: 100ms, 200ms, 400ms, 800ms, 1600ms, ...
// Custom exponential backoff with factor 1.5
const gentleExponential = Schedule.exponential("200 millis", 1.5)
// Delays: 200ms, 300ms, 450ms, 675ms, 1012ms, ...
// Retry with exponential backoff (limited to 5 attempts)
const retryPolicy = Schedule.max([
Schedule.exponential("50 millis"),
Schedule.recurs(5)
])
const program = Effect.gen(function*() {
let attempt = 0
const result = yield* Effect.retry(
Effect.gen(function*() {
attempt++
if (attempt < 4) {
yield* Console.log(`Attempt ${attempt} failed, retrying...`)
return yield* Effect.fail(new RetryFailure({ message: `Failure ${attempt}` }))
}
return `Success on attempt ${attempt}`
}),
retryPolicy
)
yield* Console.log(`Final result: ${result}`)
})
// Will retry with delays: 50ms, 100ms, 200ms before success
exponential = (
base: Duration.Inputbase: import DurationDuration.type Duration.Input = /*unresolved*/ anyInput,
factor: numberfactor: number = 2
): interface Schedule<out Output, in Input = unknown, out Error = never, out Env = never>A Schedule defines a strategy for repeating or retrying effects based on some policy.
Example (Defining retry and repeat schedules)
import { Console, Data, Effect, Schedule } from "effect"
class NetworkError extends Data.TaggedError("NetworkError")<{
readonly attempt: number
}> {}
// Basic retry schedule - retry up to 3 times with exponential backoff
const retrySchedule = Schedule.max([
Schedule.exponential("100 millis"),
Schedule.recurs(3)
])
// Basic repeat schedule - repeat every 30 seconds forever
const repeatSchedule: Schedule.Schedule<number, unknown, never> = Schedule
.spaced("30 seconds")
const program = Effect.gen(function*() {
let attempts = 0
const result1 = yield* Effect.retry(
Effect.gen(function*() {
attempts++
if (attempts < 3) {
return yield* Effect.fail(new NetworkError({ attempt: attempts }))
}
return "Success"
}),
retrySchedule
)
console.log(result1) // "Success"
yield* Console.log("heartbeat").pipe(
Effect.repeat(repeatSchedule.pipe(Schedule.upTo({ times: 5 })))
)
})
The Schedule namespace contains types and utilities for working with schedules.
Schedule<import DurationDuration.type Duration.Duration = /*unresolved*/ anyDuration> => {
const const baseMillis: anybaseMillis = import DurationDuration.toMillis(import DurationDuration.fromInputUnsafe(base: Duration.Inputbase))
return const fromStepWithMetadata: <
Input,
Output,
EnvX,
ErrorX,
Error,
Env
>(
step: Effect<
(
options: InputMetadata<Input>
) => Pull.Pull<
[Output, Duration.Duration],
ErrorX,
Output,
EnvX
>,
Error,
Env
>
) => Schedule<
Output,
Input,
Error | Pull.ExcludeDone<ErrorX>,
Env | EnvX
>
Creates a Schedule from a step function that receives metadata about the schedule's execution.
Example (Creating a metadata-aware schedule)
import { Cause, Duration, Effect, Schedule } from "effect"
const firstThreeInputs = Schedule.fromStepWithMetadata(Effect.succeed((metadata: Schedule.InputMetadata<string>) => {
if (metadata.attempt > 3) {
return Cause.done("finished")
}
return Effect.succeed([
`attempt ${metadata.attempt}: ${metadata.input}`,
Duration.millis(250)
] as [string, Duration.Duration])
}))
fromStepWithMetadata(import effecteffect.const succeed: <A>(
value: A
) => Effect.Effect<A>
succeed((meta: InputMetadata<unknown>(parameter) meta: {
input: Input;
attempt: number;
start: number;
now: number;
elapsed: number;
elapsedSincePrevious: number;
}
meta) => {
const const duration: Duration.Durationconst duration: {
value: DurationValue;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
duration = import DurationDuration.millis(const baseMillis: anybaseMillis * var Math: MathAn intrinsic object that provides basic mathematics functionality and constants.
Math.Math.pow(x: number, y: number): numberReturns the value of a base expression taken to a specified power.
pow(factor: numberfactor, meta: InputMetadata<unknown>(parameter) meta: {
input: Input;
attempt: number;
start: number;
now: number;
elapsed: number;
elapsedSincePrevious: number;
}
meta.attempt - 1))
return import effecteffect.const succeed: <A>(
value: A
) => Effect.Effect<A>
succeed([const duration: Duration.Durationconst duration: {
value: DurationValue;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
duration, const duration: Duration.Durationconst duration: {
value: DurationValue;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
duration])
}))
}