Skip to content

Examples

These examples demonstrate different approaches to handling timeouts, retries, and periodic execution using Effect. Each scenario ensures that the application remains responsive and resilient to failures while adapting dynamically to various conditions.

When calling third-party APIs, it is often necessary to enforce timeouts and implement retry mechanisms to handle transient failures. In this example, the API call retries up to two times in case of failure and will be interrupted if it takes longer than 4 seconds.

Example (Retrying an API Call with a Timeout)

import {
import Console
Console
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
// Function to make the API call
const
const getJson: (url: string) => Effect.Effect<unknown, UnknownException, never>
getJson
= (
url: string
url
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tryPromise: <unknown>(evaluate: (signal: AbortSignal) => PromiseLike<unknown>) => Effect.Effect<unknown, UnknownException, never> (+1 overload)

Creates an Effect that represents an asynchronous computation that might fail.

When to Use

In situations where you need to perform asynchronous operations that might fail, such as fetching data from an API, you can use the tryPromise constructor. This constructor is designed to handle operations that could throw exceptions by capturing those exceptions and transforming them into manageable errors.

Error Handling

There are two ways to handle errors with tryPromise:

  1. If you don't provide a catch function, the error is caught and the effect fails with an UnknownException.
  2. If you provide a catch function, the error is caught and the catch function maps it to an error of type E.

Interruptions

An optional AbortSignal can be provided to allow for interruption of the wrapped Promise API.

@seepromise if the effectful computation is asynchronous and does not throw errors.

@example

// Title: Fetching a TODO Item
import { Effect } from "effect"
const getTodo = (id: number) =>
// Will catch any errors and propagate them as UnknownException
Effect.tryPromise(() =>
fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
)
// ┌─── Effect<Response, UnknownException, never>
// ▼
const program = getTodo(1)

@example

// Title: Custom Error Handling import { Effect } from "effect"

const getTodo = (id: number) => Effect.tryPromise({ try: () => fetch(https://jsonplaceholder.typicode.com/todos/${id}), // remap the error catch: (unknown) => new Error(something went wrong ${unknown}) })

// ┌─── Effect<Response, Error, never> // ▼ const program = getTodo(1)

@since2.0.0

tryPromise
(() =>
function fetch(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>
fetch
(
url: string
url
).
Promise<Response>.then<unknown, never>(onfulfilled?: ((value: Response) => unknown) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<unknown>

Attaches callbacks for the resolution and/or rejection of the Promise.

@paramonfulfilled The callback to execute when the Promise is resolved.

@paramonrejected The callback to execute when the Promise is rejected.

@returnsA Promise for the completion of which ever callback is executed.

then
((
res: Response
res
) => {
if (!
res: Response
res
.
Response.ok: boolean
ok
) {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("error")
throw new
var Error: ErrorConstructor
new (message?: string) => Error
Error
(
res: Response
res
.
Response.statusText: string
statusText
)
}
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("ok")
return
res: Response
res
.
BodyMixin.json: () => Promise<unknown>
json
() as unknown
})
)
// Program that retries the API call twice, times out after 4 seconds,
// and logs errors
const
const program: (url: string) => Effect.Effect<unknown, never, never>
program
= (
url: string
url
: string) =>
const getJson: (url: string) => Effect.Effect<unknown, UnknownException, never>
getJson
(
url: string
url
).
Pipeable.pipe<Effect.Effect<unknown, UnknownException, never>, Effect.Effect<unknown, UnknownException, never>, Effect.Effect<unknown, UnknownException | TimeoutException, never>, Effect.Effect<...>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>, cd: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const retry: <UnknownException, {
times: number;
}>(options: {
times: number;
}) => <A, R>(self: Effect.Effect<A, UnknownException, R>) => Effect.Effect<...> (+3 overloads)

Retries a failing effect based on a defined retry policy.

Details

The Effect.retry function takes an effect and a

Schedule

policy, and will automatically retry the effect if it fails, following the rules of the policy.

If the effect ultimately succeeds, the result will be returned.

If the maximum retries are exhausted and the effect still fails, the failure is propagated.

When to Use

This can be useful when dealing with intermittent failures, such as network issues or temporary resource unavailability. By defining a retry policy, you can control the number of retries, the delay between them, and when to stop retrying.

@seeretryOrElse for a version that allows you to run a fallback.

@seerepeat if your retry condition is based on successful outcomes rather than errors.

@example

// Title: Retrying with a Fixed Delay
import { Effect, Schedule } from "effect"
let count = 0
// Simulates an effect with possible failures
const task = Effect.async<string, Error>((resume) => {
if (count <= 2) {
count++
console.log("failure")
resume(Effect.fail(new Error()))
} else {
console.log("success")
resume(Effect.succeed("yay!"))
}
})
// Define a repetition policy using a fixed delay between retries
const policy = Schedule.fixed("100 millis")
const repeated = Effect.retry(task, policy)
// Effect.runPromise(repeated).then(console.log)
// Output:
// failure
// failure
// failure
// success
// yay!

@example

// Title: Retrying a Task up to 5 times
import { Effect } from "effect"
let count = 0
// Simulates an effect with possible failures
const task = Effect.async<string, Error>((resume) => {
if (count <= 2) {
count++
console.log("failure")
resume(Effect.fail(new Error()))
} else {
console.log("success")
resume(Effect.succeed("yay!"))
}
})
// Retry the task up to 5 times
// Effect.runPromise(Effect.retry(task, { times: 5 }))
// Output:
// failure
// failure
// failure
// success

@example

// Title: Retrying Until a Specific Condition is Met
import { Effect } from "effect"
let count = 0
// Define an effect that simulates varying error on each invocation
const action = Effect.failSync(() => {
console.log(`Action called ${++count} time(s)`)
return `Error ${count}`
})
// Retry the action until a specific condition is met
const program = Effect.retry(action, {
until: (err) => err === "Error 3"
})
// Effect.runPromiseExit(program).then(console.log)
// Output:
// Action called 1 time(s)
// Action called 2 time(s)
// Action called 3 time(s)
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: { _id: 'Cause', _tag: 'Fail', failure: 'Error 3' }
// }

@since2.0.0

retry
({
times: number
times
: 2 }),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const timeout: (duration: DurationInput) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | TimeoutException, R> (+1 overload)

Adds a time limit to an effect, triggering a timeout if the effect exceeds the duration.

Details

This function allows you to enforce a time limit on the execution of an effect. If the effect does not complete within the given duration, it fails with a TimeoutException. This is useful for preventing tasks from hanging indefinitely, especially in scenarios where responsiveness or resource limits are critical.

The returned effect will either:

  • Succeed with the original effect's result if it completes within the specified duration.
  • Fail with a TimeoutException if the time limit is exceeded.

@seetimeoutFail for a version that raises a custom error.

@seetimeoutFailCause for a version that raises a custom defect.

@seetimeoutTo for a version that allows specifying both success and timeout handlers.

@example

import { Effect } from "effect"
const task = Effect.gen(function* () {
console.log("Start processing...")
yield* Effect.sleep("2 seconds") // Simulates a delay in processing
console.log("Processing complete.")
return "Result"
})
// Output will show a TimeoutException as the task takes longer
// than the specified timeout duration
const timedEffect = task.pipe(Effect.timeout("1 second"))
// Effect.runPromiseExit(timedEffect).then(console.log)
// Output:
// Start processing...
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: {
// _id: 'Cause',
// _tag: 'Fail',
// failure: { _tag: 'TimeoutException' }
// }
// }

@since2.0.0

timeout
("4 seconds"),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const catchAll: <any, void, never, never>(f: (e: any) => Effect.Effect<void, never, never>) => <A, R>(self: Effect.Effect<A, any, R>) => Effect.Effect<void | A, never, R> (+1 overload)

Handles all errors in an effect by providing a fallback effect.

Details

This function catches any errors that may occur during the execution of an effect and allows you to handle them by specifying a fallback effect. This ensures that the program continues without failing by recovering from errors using the provided fallback logic.

Note: This function only handles recoverable errors. It will not recover from unrecoverable defects.

@seecatchAllCause for a version that can recover from both recoverable and unrecoverable errors.

@example

// Title: Providing Recovery Logic for Recoverable Errors
import { Effect, Random } from "effect"
class HttpError {
readonly _tag = "HttpError"
}
class ValidationError {
readonly _tag = "ValidationError"
}
// ┌─── Effect<string, HttpError | ValidationError, never>
// ▼
const program = Effect.gen(function* () {
const n1 = yield* Random.next
const n2 = yield* Random.next
if (n1 < 0.5) {
yield* Effect.fail(new HttpError())
}
if (n2 < 0.5) {
yield* Effect.fail(new ValidationError())
}
return "some result"
})
// ┌─── Effect<string, never, never>
// ▼
const recovered = program.pipe(
Effect.catchAll((error) =>
Effect.succeed(`Recovering from ${error._tag}`)
)
)

@since2.0.0

catchAll
(
import Console
Console
.
const error: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

error
)
)
// Test case: successful API response
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <unknown, never>(effect: Effect.Effect<unknown, never, never>, options?: RunForkOptions) => RuntimeFiber<unknown, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: (url: string) => Effect.Effect<unknown, never, never>
program
("https://dummyjson.com/products/1?delay=1000"))
/*
Output:
ok
*/
// Test case: API call exceeding timeout limit
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <unknown, never>(effect: Effect.Effect<unknown, never, never>, options?: RunForkOptions) => RuntimeFiber<unknown, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: (url: string) => Effect.Effect<unknown, never, never>
program
("https://dummyjson.com/products/1?delay=5000"))
/*
Output:
TimeoutException: Operation timed out before the specified duration of '4s' elapsed
*/
// Test case: API returning an error response
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <unknown, never>(effect: Effect.Effect<unknown, never, never>, options?: RunForkOptions) => RuntimeFiber<unknown, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: (url: string) => Effect.Effect<unknown, never, never>
program
("https://dummyjson.com/auth/products/1?delay=500"))
/*
Output:
error
error
error
UnknownException: An unknown error occurred
*/

Sometimes, retries should only happen for certain error conditions. For example, if an API call fails with a 401 Unauthorized response, retrying might make sense, while a 404 Not Found error should not trigger a retry.

Example (Retrying Only on Specific Error Codes)

import {
import Console
Console
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
// Custom error class for handling status codes
class
class Err
Err
extends
var Error: ErrorConstructor
Error
{
constructor(
message: string
message
: string, readonly
Err.status: number
status
: number) {
super(
message: string
message
)
}
}
// Function to make the API call
const
const getJson: (url: string) => Effect.Effect<unknown, Err, never>
getJson
= (
url: string
url
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tryPromise: <unknown, Err>(options: {
readonly try: (signal: AbortSignal) => PromiseLike<unknown>;
readonly catch: (error: unknown) => Err;
}) => Effect.Effect<unknown, Err, never> (+1 overload)

Creates an Effect that represents an asynchronous computation that might fail.

When to Use

In situations where you need to perform asynchronous operations that might fail, such as fetching data from an API, you can use the tryPromise constructor. This constructor is designed to handle operations that could throw exceptions by capturing those exceptions and transforming them into manageable errors.

Error Handling

There are two ways to handle errors with tryPromise:

  1. If you don't provide a catch function, the error is caught and the effect fails with an UnknownException.
  2. If you provide a catch function, the error is caught and the catch function maps it to an error of type E.

Interruptions

An optional AbortSignal can be provided to allow for interruption of the wrapped Promise API.

@seepromise if the effectful computation is asynchronous and does not throw errors.

@example

// Title: Fetching a TODO Item
import { Effect } from "effect"
const getTodo = (id: number) =>
// Will catch any errors and propagate them as UnknownException
Effect.tryPromise(() =>
fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
)
// ┌─── Effect<Response, UnknownException, never>
// ▼
const program = getTodo(1)

@example

// Title: Custom Error Handling import { Effect } from "effect"

const getTodo = (id: number) => Effect.tryPromise({ try: () => fetch(https://jsonplaceholder.typicode.com/todos/${id}), // remap the error catch: (unknown) => new Error(something went wrong ${unknown}) })

// ┌─── Effect<Response, Error, never> // ▼ const program = getTodo(1)

@since2.0.0

tryPromise
({
try: (signal: AbortSignal) => PromiseLike<unknown>
try
: () =>
function fetch(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>
fetch
(
url: string
url
).
Promise<Response>.then<unknown, never>(onfulfilled?: ((value: Response) => unknown) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<unknown>

Attaches callbacks for the resolution and/or rejection of the Promise.

@paramonfulfilled The callback to execute when the Promise is resolved.

@paramonrejected The callback to execute when the Promise is rejected.

@returnsA Promise for the completion of which ever callback is executed.

then
((
res: Response
res
) => {
if (!
res: Response
res
.
Response.ok: boolean
ok
) {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
(
res: Response
res
.
Response.status: number
status
)
throw new
constructor Err(message: string, status: number): Err
Err
(
res: Response
res
.
Response.statusText: string
statusText
,
res: Response
res
.
Response.status: number
status
)
}
return
res: Response
res
.
BodyMixin.json: () => Promise<unknown>
json
() as unknown
}),
catch: (error: unknown) => Err
catch
: (
e: unknown
e
) =>
e: unknown
e
as
class Err
Err
})
// Program that retries only when the error status is 401 (Unauthorized)
const
const program: (url: string) => Effect.Effect<unknown, never, never>
program
= (
url: string
url
: string) =>
const getJson: (url: string) => Effect.Effect<unknown, Err, never>
getJson
(
url: string
url
).
Pipeable.pipe<Effect.Effect<unknown, Err, never>, Effect.Effect<unknown, Err, never>, Effect.Effect<unknown, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<unknown, Err, never>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const retry: <Err, {
while: (err: Err) => boolean;
}>(options: {
while: (err: Err) => boolean;
}) => <A, R>(self: Effect.Effect<A, Err, R>) => Effect.Effect<A, Err, R> (+3 overloads)

Retries a failing effect based on a defined retry policy.

Details

The Effect.retry function takes an effect and a

Schedule

policy, and will automatically retry the effect if it fails, following the rules of the policy.

If the effect ultimately succeeds, the result will be returned.

If the maximum retries are exhausted and the effect still fails, the failure is propagated.

When to Use

This can be useful when dealing with intermittent failures, such as network issues or temporary resource unavailability. By defining a retry policy, you can control the number of retries, the delay between them, and when to stop retrying.

@seeretryOrElse for a version that allows you to run a fallback.

@seerepeat if your retry condition is based on successful outcomes rather than errors.

@example

// Title: Retrying with a Fixed Delay
import { Effect, Schedule } from "effect"
let count = 0
// Simulates an effect with possible failures
const task = Effect.async<string, Error>((resume) => {
if (count <= 2) {
count++
console.log("failure")
resume(Effect.fail(new Error()))
} else {
console.log("success")
resume(Effect.succeed("yay!"))
}
})
// Define a repetition policy using a fixed delay between retries
const policy = Schedule.fixed("100 millis")
const repeated = Effect.retry(task, policy)
// Effect.runPromise(repeated).then(console.log)
// Output:
// failure
// failure
// failure
// success
// yay!

@example

// Title: Retrying a Task up to 5 times
import { Effect } from "effect"
let count = 0
// Simulates an effect with possible failures
const task = Effect.async<string, Error>((resume) => {
if (count <= 2) {
count++
console.log("failure")
resume(Effect.fail(new Error()))
} else {
console.log("success")
resume(Effect.succeed("yay!"))
}
})
// Retry the task up to 5 times
// Effect.runPromise(Effect.retry(task, { times: 5 }))
// Output:
// failure
// failure
// failure
// success

@example

// Title: Retrying Until a Specific Condition is Met
import { Effect } from "effect"
let count = 0
// Define an effect that simulates varying error on each invocation
const action = Effect.failSync(() => {
console.log(`Action called ${++count} time(s)`)
return `Error ${count}`
})
// Retry the action until a specific condition is met
const program = Effect.retry(action, {
until: (err) => err === "Error 3"
})
// Effect.runPromiseExit(program).then(console.log)
// Output:
// Action called 1 time(s)
// Action called 2 time(s)
// Action called 3 time(s)
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: { _id: 'Cause', _tag: 'Fail', failure: 'Error 3' }
// }

@since2.0.0

retry
({
while: (err: Err) => boolean
while
: (
err: Err
err
) =>
err: Err
err
.
Err.status: number
status
=== 401 }),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const catchAll: <any, void, never, never>(f: (e: any) => Effect.Effect<void, never, never>) => <A, R>(self: Effect.Effect<A, any, R>) => Effect.Effect<void | A, never, R> (+1 overload)

Handles all errors in an effect by providing a fallback effect.

Details

This function catches any errors that may occur during the execution of an effect and allows you to handle them by specifying a fallback effect. This ensures that the program continues without failing by recovering from errors using the provided fallback logic.

Note: This function only handles recoverable errors. It will not recover from unrecoverable defects.

@seecatchAllCause for a version that can recover from both recoverable and unrecoverable errors.

@example

// Title: Providing Recovery Logic for Recoverable Errors
import { Effect, Random } from "effect"
class HttpError {
readonly _tag = "HttpError"
}
class ValidationError {
readonly _tag = "ValidationError"
}
// ┌─── Effect<string, HttpError | ValidationError, never>
// ▼
const program = Effect.gen(function* () {
const n1 = yield* Random.next
const n2 = yield* Random.next
if (n1 < 0.5) {
yield* Effect.fail(new HttpError())
}
if (n2 < 0.5) {
yield* Effect.fail(new ValidationError())
}
return "some result"
})
// ┌─── Effect<string, never, never>
// ▼
const recovered = program.pipe(
Effect.catchAll((error) =>
Effect.succeed(`Recovering from ${error._tag}`)
)
)

@since2.0.0

catchAll
(
import Console
Console
.
const error: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

error
)
)
// Test case: API returns 401 (triggers multiple retries)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <unknown, never>(effect: Effect.Effect<unknown, never, never>, options?: RunForkOptions) => RuntimeFiber<unknown, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: (url: string) => Effect.Effect<unknown, never, never>
program
("https://dummyjson.com/auth/products/1?delay=1000")
)
/*
Output:
401
401
401
401
...
*/
// Test case: API returns 404 (no retries)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <unknown, never>(effect: Effect.Effect<unknown, never, never>, options?: RunForkOptions) => RuntimeFiber<unknown, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: (url: string) => Effect.Effect<unknown, never, never>
program
("https://dummyjson.com/-"))
/*
Output:
404
Err [Error]: Not Found
*/

Some API errors, such as 429 Too Many Requests, include a Retry-After header that specifies how long to wait before retrying. Instead of using a fixed delay, we can dynamically adjust the retry interval based on this value.

Example (Using the Retry-After Header for Retry Delays)

This approach ensures that the retry delay adapts dynamically to the server’s response, preventing unnecessary retries while respecting the provided Retry-After value.

import {
import Duration
Duration
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Schedule
Schedule
} from "effect"
// Custom error class representing a "Too Many Requests" response
class
class TooManyRequestsError
TooManyRequestsError
{
readonly
TooManyRequestsError._tag: "TooManyRequestsError"
_tag
= "TooManyRequestsError"
constructor(readonly
TooManyRequestsError.retryAfter: number
retryAfter
: number) {}
}
let
let n: number
n
= 1
const
const request: Effect.Effect<string, TooManyRequestsError, never>
request
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<never, TooManyRequestsError, never>>, string>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<never, TooManyRequestsError, never>>, string, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
// Simulate failing a particular number of times
if (
let n: number
n
< 3) {
const
const retryAfter: number
retryAfter
=
let n: number
n
* 500
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
(`Attempt #${
let n: number
n
++}, retry after ${
const retryAfter: number
retryAfter
} millis...`)
// Simulate retrieving the retry-after header
return yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <TooManyRequestsError>(error: TooManyRequestsError) => Effect.Effect<never, TooManyRequestsError, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

@seesucceed to create an effect that represents a successful value.

@example

// Title: Creating a Failed Effect
import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@since2.0.0

fail
(new
constructor TooManyRequestsError(retryAfter: number): TooManyRequestsError
TooManyRequestsError
(
const retryAfter: number
retryAfter
))
}
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("Done")
return "some result"
})
// Retry policy that extracts the retry delay from the error
const
const policy: Schedule.Schedule<[TooManyRequestsError, number], TooManyRequestsError, never>
policy
=
import Schedule
Schedule
.
const identity: <TooManyRequestsError>() => Schedule.Schedule<TooManyRequestsError, TooManyRequestsError, never>

Creates a schedule that always recurs, passing inputs directly as outputs.

Details

This schedule runs indefinitely, returning each input value as its output without modification. It effectively acts as a pass-through that simply echoes its input values at each step.

@since2.0.0

identity
<
class TooManyRequestsError
TooManyRequestsError
>().
Pipeable.pipe<Schedule.Schedule<TooManyRequestsError, TooManyRequestsError, never>, Schedule.Schedule<TooManyRequestsError, TooManyRequestsError, never>, Schedule.Schedule<...>>(this: Schedule.Schedule<...>, ab: (_: Schedule.Schedule<...>) => Schedule.Schedule<...>, bc: (_: Schedule.Schedule<...>) => Schedule.Schedule<...>): Schedule.Schedule<...> (+21 overloads)
pipe
(
import Schedule
Schedule
.
const addDelay: <TooManyRequestsError>(f: (out: TooManyRequestsError) => Duration.DurationInput) => <In, R>(self: Schedule.Schedule<TooManyRequestsError, In, R>) => Schedule.Schedule<...> (+1 overload)

Adds a delay to every interval in a schedule.

Details

This function modifies a given schedule by applying an additional delay to every interval it defines. The delay is determined by the provided function, which takes the schedule's output and returns a delay duration.

@seeaddDelayEffect If you need to compute the delay using an effectful function.

@since2.0.0

addDelay
((
error: TooManyRequestsError
error
) =>
error: TooManyRequestsError
error
.
TooManyRequestsError._tag: "TooManyRequestsError"
_tag
=== "TooManyRequestsError"
? // Wait for the specified retry-after duration
import Duration
Duration
.
const millis: (millis: number) => Duration.Duration

@since2.0.0

millis
(
error: TooManyRequestsError
error
.
TooManyRequestsError.retryAfter: number
retryAfter
)
:
import Duration
Duration
.
const zero: Duration.Duration

@since2.0.0

zero
),
// Limit retries to 5 attempts
import Schedule
Schedule
.
const intersect: <number, unknown, never>(that: Schedule.Schedule<number, unknown, never>) => <Out, In, R>(self: Schedule.Schedule<Out, In, R>) => Schedule.Schedule<[Out, number], In, R> (+1 overload)

Combines two schedules, continuing only if both schedules want to continue, using the longer delay.

Details

This function takes two schedules and creates a new schedule that only continues execution if both schedules allow it. The interval between recurrences is determined by the longer delay between the two schedules.

The output of the resulting schedule is a tuple containing the outputs of both schedules. The input type is the intersection of both schedules' input types.

This is useful when coordinating multiple scheduling conditions where execution should proceed only when both schedules permit it.

@seeintersectWith If you need to use a custom merge function.

@since2.0.0

intersect
(
import Schedule
Schedule
.
const recurs: (n: number) => Schedule.Schedule<number>

A schedule that recurs a fixed number of times before terminating.

Details

This schedule will continue executing until it has been stepped n times, after which it will stop. The output of the schedule is the current count of recurrences.

@since2.0.0

recurs
(5))
)
const
const program: Effect.Effect<string, TooManyRequestsError, never>
program
=
const request: Effect.Effect<string, TooManyRequestsError, never>
request
.
Pipeable.pipe<Effect.Effect<string, TooManyRequestsError, never>, Effect.Effect<string, TooManyRequestsError, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const retry: <[TooManyRequestsError, number], TooManyRequestsError, never>(policy: Schedule.Schedule<[TooManyRequestsError, number], TooManyRequestsError, never>) => <A, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+3 overloads)

Retries a failing effect based on a defined retry policy.

Details

The Effect.retry function takes an effect and a

Schedule

policy, and will automatically retry the effect if it fails, following the rules of the policy.

If the effect ultimately succeeds, the result will be returned.

If the maximum retries are exhausted and the effect still fails, the failure is propagated.

When to Use

This can be useful when dealing with intermittent failures, such as network issues or temporary resource unavailability. By defining a retry policy, you can control the number of retries, the delay between them, and when to stop retrying.

@seeretryOrElse for a version that allows you to run a fallback.

@seerepeat if your retry condition is based on successful outcomes rather than errors.

@example

// Title: Retrying with a Fixed Delay
import { Effect, Schedule } from "effect"
let count = 0
// Simulates an effect with possible failures
const task = Effect.async<string, Error>((resume) => {
if (count <= 2) {
count++
console.log("failure")
resume(Effect.fail(new Error()))
} else {
console.log("success")
resume(Effect.succeed("yay!"))
}
})
// Define a repetition policy using a fixed delay between retries
const policy = Schedule.fixed("100 millis")
const repeated = Effect.retry(task, policy)
// Effect.runPromise(repeated).then(console.log)
// Output:
// failure
// failure
// failure
// success
// yay!

@example

// Title: Retrying a Task up to 5 times
import { Effect } from "effect"
let count = 0
// Simulates an effect with possible failures
const task = Effect.async<string, Error>((resume) => {
if (count <= 2) {
count++
console.log("failure")
resume(Effect.fail(new Error()))
} else {
console.log("success")
resume(Effect.succeed("yay!"))
}
})
// Retry the task up to 5 times
// Effect.runPromise(Effect.retry(task, { times: 5 }))
// Output:
// failure
// failure
// failure
// success

@example

// Title: Retrying Until a Specific Condition is Met
import { Effect } from "effect"
let count = 0
// Define an effect that simulates varying error on each invocation
const action = Effect.failSync(() => {
console.log(`Action called ${++count} time(s)`)
return `Error ${count}`
})
// Retry the action until a specific condition is met
const program = Effect.retry(action, {
until: (err) => err === "Error 3"
})
// Effect.runPromiseExit(program).then(console.log)
// Output:
// Action called 1 time(s)
// Action called 2 time(s)
// Action called 3 time(s)
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: { _id: 'Cause', _tag: 'Fail', failure: 'Error 3' }
// }

@since2.0.0

retry
(
const policy: Schedule.Schedule<[TooManyRequestsError, number], TooManyRequestsError, never>
policy
))
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <string, TooManyRequestsError>(effect: Effect.Effect<string, TooManyRequestsError, never>, options?: RunForkOptions) => RuntimeFiber<...>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<string, TooManyRequestsError, never>
program
)
/*
Output:
Attempt #1, retry after 500 millis...
Attempt #2, retry after 1000 millis...
Done
*/

There are cases where we need to repeatedly perform an action at fixed intervals until another longer-running task finishes. This pattern is common in polling mechanisms or periodic logging.

Example (Running a Scheduled Task Until Completion)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Console
Console
,
import Schedule
Schedule
} from "effect"
// Define a long-running effect
// (e.g., a task that takes 5 seconds to complete)
const
const longRunningEffect: Effect.Effect<void, never, never>
longRunningEffect
=
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
("done").
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const delay: (duration: DurationInput) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Delays the execution of an effect by a specified Duration.

**Details

This function postpones the execution of the provided effect by the specified duration. The duration can be provided in various formats supported by the Duration module.

Internally, this function does not block the thread; instead, it uses an efficient, non-blocking mechanism to introduce the delay.

@example

import { Console, Effect } from "effect"
const task = Console.log("Task executed")
const program = Console.log("start").pipe(
Effect.andThen(
// Delays the log message by 2 seconds
task.pipe(Effect.delay("2 seconds"))
)
)
// Effect.runFork(program)
// Output:
// start
// Task executed

@since2.0.0

delay
("5 seconds")
)
// Define an action to run periodically
const
const action: Effect.Effect<void, never, never>
action
=
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
("action...")
// Define a fixed interval schedule
const
const schedule: Schedule.Schedule<number, unknown, never>
schedule
=
import Schedule
Schedule
.
const fixed: (interval: DurationInput) => Schedule.Schedule<number>

Creates a schedule that recurs at a fixed interval.

Details

This schedule executes at regular, evenly spaced intervals, returning the number of times it has run so far. If the action being executed takes longer than the interval, the next execution will happen immediately to prevent "pile-ups," ensuring that the schedule remains consistent without overlapping executions.

|-----interval-----|-----interval-----|-----interval-----|
|---------action--------||action|-----|action|-----------|

@seespaced If you need to run from the end of the last execution.

@since2.0.0

fixed
("1.5 seconds")
// Run the action repeatedly until the long-running task completes
const
const program: Effect.Effect<number | void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const race: <number, never, never, void, never, never>(self: Effect.Effect<number, never, never>, that: Effect.Effect<void, never, never>) => Effect.Effect<number | void, never, never> (+1 overload)

Races two effects and returns the result of the first successful one.

Details

This function takes two effects and runs them concurrently. The first effect that successfully completes will determine the result of the race, and the other effect will be interrupted.

If neither effect succeeds, the function will fail with a Cause containing all the errors.

When to Use

This is useful when you want to run two effects concurrently, but only care about the first one to succeed. It is commonly used in cases like timeouts, retries, or when you want to optimize for the faster response without worrying about the other effect.

Handling Success or Failure with Either

If you want to handle the result of whichever task completes first, whether it succeeds or fails, you can use the Effect.either function. This function wraps the result in an Either type, allowing you to see if the result was a success (Right) or a failure (Left).

@seeraceAll for a version that handles multiple effects.

@seeraceFirst for a version that returns the result of the first effect to complete.

@example

// Title: Both Tasks Succeed
import { Effect, Console } from "effect"
const task1 = Effect.succeed("task1").pipe(
Effect.delay("200 millis"),
Effect.tap(Console.log("task1 done")),
Effect.onInterrupt(() => Console.log("task1 interrupted"))
)
const task2 = Effect.succeed("task2").pipe(
Effect.delay("100 millis"),
Effect.tap(Console.log("task2 done")),
Effect.onInterrupt(() => Console.log("task2 interrupted"))
)
const program = Effect.race(task1, task2)
// Effect.runFork(program)
// Output:
// task1 done
// task2 interrupted

@example

// Title: One Task Fails, One Succeeds
import { Effect, Console } from "effect"
const task1 = Effect.fail("task1").pipe(
Effect.delay("100 millis"),
Effect.tap(Console.log("task1 done")),
Effect.onInterrupt(() => Console.log("task1 interrupted"))
)
const task2 = Effect.succeed("task2").pipe(
Effect.delay("200 millis"),
Effect.tap(Console.log("task2 done")),
Effect.onInterrupt(() => Console.log("task2 interrupted"))
)
const program = Effect.race(task1, task2)
// Effect.runFork(program)
// Output:
// task2 done

@example

// Title: Both Tasks Fail
import { Effect, Console } from "effect"
const task1 = Effect.fail("task1").pipe(
Effect.delay("100 millis"),
Effect.tap(Console.log("task1 done")),
Effect.onInterrupt(() => Console.log("task1 interrupted"))
)
const task2 = Effect.fail("task2").pipe(
Effect.delay("200 millis"),
Effect.tap(Console.log("task2 done")),
Effect.onInterrupt(() => Console.log("task2 interrupted"))
)
const program = Effect.race(task1, task2)
// Effect.runPromiseExit(program).then(console.log)
// Output:
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: {
// _id: 'Cause',
// _tag: 'Parallel',
// left: { _id: 'Cause', _tag: 'Fail', failure: 'task1' },
// right: { _id: 'Cause', _tag: 'Fail', failure: 'task2' }
// }
// }

@example

// Title: Handling Success or Failure with Either
import { Effect, Console } from "effect"
const task1 = Effect.fail("task1").pipe(
Effect.delay("100 millis"),
Effect.tap(Console.log("task1 done")),
Effect.onInterrupt(() => Console.log("task1 interrupted"))
)
const task2 = Effect.succeed("task2").pipe(
Effect.delay("200 millis"),
Effect.tap(Console.log("task2 done")),
Effect.onInterrupt(() => Console.log("task2 interrupted"))
)
// Run both tasks concurrently, wrapping the result
// in Either to capture success or failure
const program = Effect.race(Effect.either(task1), Effect.either(task2))
// Effect.runPromise(program).then(console.log)
// Output:
// task2 interrupted
// { _id: 'Either', _tag: 'Left', left: 'task1' }

@since2.0.0

race
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const repeat: <void, never, never, number, never>(self: Effect.Effect<void, never, never>, schedule: Schedule.Schedule<number, void, never>) => Effect.Effect<number, never, never> (+3 overloads)

Repeats an effect based on a specified schedule or until the first failure.

Details

This function executes an effect repeatedly according to the given schedule. Each repetition occurs after the initial execution of the effect, meaning that the schedule determines the number of additional repetitions. For example, using Schedule.once will result in the effect being executed twice (once initially and once as part of the repetition).

If the effect succeeds, it is repeated according to the schedule. If it fails, the repetition stops immediately, and the failure is returned.

The schedule can also specify delays between repetitions, making it useful for tasks like retrying operations with backoff, periodic execution, or performing a series of dependent actions.

You can combine schedules for more advanced repetition logic, such as adding delays, limiting recursions, or dynamically adjusting based on the outcome of each execution.

@example

// Success Example
import { Effect, Schedule, Console } from "effect"
const action = Console.log("success")
const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis")
const program = Effect.repeat(action, policy)
// Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`))

@example

// Failure Example import { Effect, Schedule } from "effect"

let count = 0

// Define an async effect that simulates an action with possible failures const action = Effect.async<string, string>((resume) => { if (count > 1) { console.log("failure") resume(Effect.fail("Uh oh!")) } else { count++ console.log("success") resume(Effect.succeed("yay!")) } })

const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis") const program = Effect.repeat(action, policy)

// Effect.runPromiseExit(program).then(console.log)

@since2.0.0

repeat
(
const action: Effect.Effect<void, never, never>
action
,
const schedule: Schedule.Schedule<number, unknown, never>
schedule
),
const longRunningEffect: Effect.Effect<void, never, never>
longRunningEffect
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runPromise: <number | void, never>(effect: Effect.Effect<number | void, never, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<number | void>

Executes an effect and returns the result as a Promise.

Details

This function runs an effect and converts its result into a Promise. If the effect succeeds, the Promise will resolve with the successful result. If the effect fails, the Promise will reject with an error, which includes the failure details of the effect.

The optional options parameter allows you to pass an AbortSignal for cancellation, enabling more fine-grained control over asynchronous tasks.

When to Use

Use this function when you need to execute an effect and work with its result in a promise-based system, such as when integrating with third-party libraries that expect Promise results.

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@example

// Title: Running a Successful Effect as a Promise
import { Effect } from "effect"
// Effect.runPromise(Effect.succeed(1)).then(console.log)
// Output: 1

@example

//Example: Handling a Failing Effect as a Rejected Promise import { Effect } from "effect"

// Effect.runPromise(Effect.fail("my error")).catch(console.error) // Output: // (FiberFailure) Error: my error

@since2.0.0

runPromise
(
const program: Effect.Effect<number | void, never, never>
program
)
/*
Output:
action...
action...
action...
action...
done
*/