Skip to content

Semaphore

A semaphore is a synchronization mechanism used to manage access to a shared resource. In Effect, semaphores help control resource access or coordinate tasks within asynchronous, concurrent operations.

A semaphore acts as a generalized mutex, allowing a set number of permits to be held and released concurrently. Permits act like tickets, giving tasks or fibers controlled access to a shared resource. When no permits are available, tasks trying to acquire one will wait until a permit is released.

The Effect.makeSemaphore function initializes a semaphore with a specified number of permits. Each permit allows one task to access a resource or perform an operation concurrently, and multiple permits enable a configurable level of concurrency.

Example (Creating a Semaphore with 3 Permits)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
// Create a semaphore with 3 permits
const
const mutex: Effect.Effect<Effect.Semaphore, never, never>
mutex
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const makeSemaphore: (permits: number) => Effect.Effect<Effect.Semaphore>

Creates a new semaphore with the specified number of permits.

Details

This function initializes a semaphore that controls concurrent access to a shared resource. The number of permits determines how many tasks can access the resource concurrently.

@example

import { Effect } from "effect"
// Create a semaphore with 3 permits
const mutex = Effect.makeSemaphore(3)

@since2.0.0

makeSemaphore
(3)

The withPermits method lets you specify the number of permits required to run an effect. Once the specified permits are available, it runs the effect, automatically releasing the permits when the task completes.

Example (Forcing Sequential Task Execution with a One-Permit Semaphore)

In this example, three tasks are started concurrently, but they run sequentially because the one-permit semaphore only allows one task to proceed at a time.

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const task: Effect.Effect<void, never, never>
task
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, 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* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("start")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
// Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("2 seconds")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("end")
})
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<Effect.Semaphore, never, never>> | YieldWrap<Effect.Effect<[void, void, void], never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => 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* () {
const
const mutex: Effect.Semaphore
mutex
= yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const makeSemaphore: (permits: number) => Effect.Effect<Effect.Semaphore>

Creates a new semaphore with the specified number of permits.

Details

This function initializes a semaphore that controls concurrent access to a shared resource. The number of permits determines how many tasks can access the resource concurrently.

@example

import { Effect } from "effect"
// Create a semaphore with 3 permits
const mutex = Effect.makeSemaphore(3)

@since2.0.0

makeSemaphore
(1)
// Wrap the task to require one permit, forcing sequential execution
const
const semTask: Effect.Effect<void, never, never>
semTask
=
const mutex: Effect.Semaphore
mutex
.
Semaphore.withPermits(permits: number): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>

Runs an effect with the given number of permits and releases the permits when the effect completes.

Details

This function acquires the specified number of permits before executing the provided effect. Once the effect finishes, the permits are released. If insufficient permits are available, the function will wait until they are released by other tasks.

withPermits
(1)(
const task: Effect.Effect<void, never, never>
task
)
.
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 withLogSpan: (label: string) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Adds a log span to an effect for tracking and logging its execution duration.

Details

This function wraps an effect with a log span, providing performance monitoring and debugging capabilities. The log span tracks the duration of the wrapped effect and logs it with the specified label. This is particularly useful when analyzing time-sensitive operations or understanding the execution time of specific tasks in your application.

The logged output will include the label and the total time taken for the operation. The span information is included in the log metadata, making it easy to trace performance metrics in logs.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.sleep("1 second")
yield* Effect.log("The job is finished!")
}).pipe(Effect.withLogSpan("myspan"))
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message="The job is finished!" myspan=1011ms

@since2.0.0

withLogSpan
("elapsed"))
// Run 3 tasks concurrently, but they execute sequentially
// due to the one-permit semaphore
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const all: <readonly [Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>], {
concurrency: "unbounded";
}>(arg: readonly [Effect.Effect<void, never, never>, Effect.Effect<...>, Effect.Effect<...>], options?: {
concurrency: "unbounded";
} | undefined) => Effect.Effect<...>

Combines multiple effects into one, returning results based on the input structure.

Details

Use this function when you need to run multiple effects and combine their results into a single output. It supports tuples, iterables, structs, and records, making it flexible for different input types.

For instance, if the input is a tuple:

// ┌─── a tuple of effects
// ▼
Effect.all([effect1, effect2, ...])

the effects are executed sequentially, and the result is a new effect containing the results as a tuple. The results in the tuple match the order of the effects passed to Effect.all.

Concurrency

You can control the execution order (e.g., sequential vs. concurrent) using the concurrency option.

Short-Circuiting Behavior

This function stops execution on the first error it encounters, this is called "short-circuiting". If any effect in the collection fails, the remaining effects will not run, and the error will be propagated. To change this behavior, you can use the mode option, which allows all effects to run and collect results as Either or Option.

The mode option

The { mode: "either" } option changes the behavior of Effect.all to ensure all effects run, even if some fail. Instead of stopping on the first failure, this mode collects both successes and failures, returning an array of Either instances where each result is either a Right (success) or a Left (failure).

Similarly, the { mode: "validate" } option uses Option to indicate success or failure. Each effect returns None for success and Some with the error for failure.

@seeforEach for iterating over elements and applying an effect.

@seeallWith for a data-last version of this function.

@example

// Title: Combining Effects in Tuples
import { Effect, Console } from "effect"
const tupleOfEffects = [
Effect.succeed(42).pipe(Effect.tap(Console.log)),
Effect.succeed("Hello").pipe(Effect.tap(Console.log))
] as const
// ┌─── Effect<[number, string], never, never>
// ▼
const resultsAsTuple = Effect.all(tupleOfEffects)
// Effect.runPromise(resultsAsTuple).then(console.log)
// Output:
// 42
// Hello
// [ 42, 'Hello' ]

@example

// Title: Combining Effects in Iterables import { Effect, Console } from "effect"

const iterableOfEffects: Iterable<Effect.Effect> = [1, 2, 3].map( (n) => Effect.succeed(n).pipe(Effect.tap(Console.log)) )

// ┌─── Effect<number[], never, never> // ▼ const resultsAsArray = Effect.all(iterableOfEffects)

// Effect.runPromise(resultsAsArray).then(console.log) // Output: // 1 // 2 // 3 // [ 1, 2, 3 ]

@example

// Title: Combining Effects in Structs import { Effect, Console } from "effect"

const structOfEffects = { a: Effect.succeed(42).pipe(Effect.tap(Console.log)), b: Effect.succeed("Hello").pipe(Effect.tap(Console.log)) }

// ┌─── Effect<{ a: number; b: string; }, never, never> // ▼ const resultsAsStruct = Effect.all(structOfEffects)

// Effect.runPromise(resultsAsStruct).then(console.log) // Output: // 42 // Hello // { a: 42, b: 'Hello' }

@example

// Title: Combining Effects in Records import { Effect, Console } from "effect"

const recordOfEffects: Record<string, Effect.Effect> = { key1: Effect.succeed(1).pipe(Effect.tap(Console.log)), key2: Effect.succeed(2).pipe(Effect.tap(Console.log)) }

// ┌─── Effect<{ [x: string]: number; }, never, never> // ▼ const resultsAsRecord = Effect.all(recordOfEffects)

// Effect.runPromise(resultsAsRecord).then(console.log) // Output: // 1 // 2 // { key1: 1, key2: 2 }

@example

// Title: Short-Circuiting Behavior import { Effect, Console } from "effect"

const program = Effect.all([ Effect.succeed("Task1").pipe(Effect.tap(Console.log)), Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), // Won't execute due to earlier failure Effect.succeed("Task3").pipe(Effect.tap(Console.log)) ])

// Effect.runPromiseExit(program).then(console.log) // Output: // Task1 // { // _id: 'Exit', // _tag: 'Failure', // cause: { _id: 'Cause', _tag: 'Fail', failure: 'Task2: Oh no!' } // }

@example

// Title: Collecting Results with mode: "either" import { Effect, Console } from "effect"

const effects = [ Effect.succeed("Task1").pipe(Effect.tap(Console.log)), Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), Effect.succeed("Task3").pipe(Effect.tap(Console.log)) ]

const program = Effect.all(effects, { mode: "either" })

// Effect.runPromiseExit(program).then(console.log) // Output: // Task1 // Task3 // { // _id: 'Exit', // _tag: 'Success', // value: [ // { _id: 'Either', _tag: 'Right', right: 'Task1' }, // { _id: 'Either', _tag: 'Left', left: 'Task2: Oh no!' }, // { _id: 'Either', _tag: 'Right', right: 'Task3' } // ] // }

@example

//Example: Collecting Results with mode: "validate" import { Effect, Console } from "effect"

const effects = [ Effect.succeed("Task1").pipe(Effect.tap(Console.log)), Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), Effect.succeed("Task3").pipe(Effect.tap(Console.log)) ]

const program = Effect.all(effects, { mode: "validate" })

// Effect.runPromiseExit(program).then((result) => console.log("%o", result)) // Output: // Task1 // Task3 // { // _id: 'Exit', // _tag: 'Failure', // cause: { // _id: 'Cause', // _tag: 'Fail', // failure: [ // { _id: 'Option', _tag: 'None' }, // { _id: 'Option', _tag: 'Some', value: 'Task2: Oh no!' }, // { _id: 'Option', _tag: 'None' } // ] // } // }

@since2.0.0

all
([
const semTask: Effect.Effect<void, never, never>
semTask
,
const semTask: Effect.Effect<void, never, never>
semTask
,
const semTask: Effect.Effect<void, never, never>
semTask
], {
concurrency: "unbounded"
concurrency
: "unbounded"
})
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, 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: Effect.Effect<void, never, never>
program
)
/*
Output:
timestamp=... level=INFO fiber=#1 message=start elapsed=3ms
timestamp=... level=INFO fiber=#1 message=end elapsed=2010ms
timestamp=... level=INFO fiber=#2 message=start elapsed=2012ms
timestamp=... level=INFO fiber=#2 message=end elapsed=4017ms
timestamp=... level=INFO fiber=#3 message=start elapsed=4018ms
timestamp=... level=INFO fiber=#3 message=end elapsed=6026ms
*/

Example (Using Multiple Permits to Control Concurrent Task Execution)

In this example, we create a semaphore with five permits and use withPermits(n) to allocate a different number of permits for each task:

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<Effect.Semaphore, never, never>> | YieldWrap<Effect.Effect<void[], never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => 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* () {
const
const mutex: Effect.Semaphore
mutex
= yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const makeSemaphore: (permits: number) => Effect.Effect<Effect.Semaphore>

Creates a new semaphore with the specified number of permits.

Details

This function initializes a semaphore that controls concurrent access to a shared resource. The number of permits determines how many tasks can access the resource concurrently.

@example

import { Effect } from "effect"
// Create a semaphore with 3 permits
const mutex = Effect.makeSemaphore(3)

@since2.0.0

makeSemaphore
(5)
const
const tasks: Effect.Effect<void, never, never>[]
tasks
= [1, 2, 3, 4, 5].
Array<number>.map<Effect.Effect<void, never, never>>(callbackfn: (value: number, index: number, array: number[]) => Effect.Effect<void, never, never>, thisArg?: any): Effect.Effect<void, never, never>[]

Calls a defined callback function on each element of an array, and returns an array that contains the results.

@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.

@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.

map
((
n: number
n
) =>
const mutex: Effect.Semaphore
mutex
.
Semaphore.withPermits(permits: number): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>

Runs an effect with the given number of permits and releases the permits when the effect completes.

Details

This function acquires the specified number of permits before executing the provided effect. Once the effect finishes, the permits are released. If insufficient permits are available, the function will wait until they are released by other tasks.

withPermits
(
n: number
n
)(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const delay: <void, never, never>(self: Effect.Effect<void, never, never>, duration: DurationInput) => Effect.Effect<void, never, never> (+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
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
(`process: ${
n: number
n
}`), "2 seconds")
)
.
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 withLogSpan: (label: string) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Adds a log span to an effect for tracking and logging its execution duration.

Details

This function wraps an effect with a log span, providing performance monitoring and debugging capabilities. The log span tracks the duration of the wrapped effect and logs it with the specified label. This is particularly useful when analyzing time-sensitive operations or understanding the execution time of specific tasks in your application.

The logged output will include the label and the total time taken for the operation. The span information is included in the log metadata, making it easy to trace performance metrics in logs.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.sleep("1 second")
yield* Effect.log("The job is finished!")
}).pipe(Effect.withLogSpan("myspan"))
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message="The job is finished!" myspan=1011ms

@since2.0.0

withLogSpan
("elapsed"))
)
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const all: <Effect.Effect<void, never, never>[], {
concurrency: "unbounded";
}>(arg: Effect.Effect<void, never, never>[], options?: {
concurrency: "unbounded";
} | undefined) => Effect.Effect<...>

Combines multiple effects into one, returning results based on the input structure.

Details

Use this function when you need to run multiple effects and combine their results into a single output. It supports tuples, iterables, structs, and records, making it flexible for different input types.

For instance, if the input is a tuple:

// ┌─── a tuple of effects
// ▼
Effect.all([effect1, effect2, ...])

the effects are executed sequentially, and the result is a new effect containing the results as a tuple. The results in the tuple match the order of the effects passed to Effect.all.

Concurrency

You can control the execution order (e.g., sequential vs. concurrent) using the concurrency option.

Short-Circuiting Behavior

This function stops execution on the first error it encounters, this is called "short-circuiting". If any effect in the collection fails, the remaining effects will not run, and the error will be propagated. To change this behavior, you can use the mode option, which allows all effects to run and collect results as Either or Option.

The mode option

The { mode: "either" } option changes the behavior of Effect.all to ensure all effects run, even if some fail. Instead of stopping on the first failure, this mode collects both successes and failures, returning an array of Either instances where each result is either a Right (success) or a Left (failure).

Similarly, the { mode: "validate" } option uses Option to indicate success or failure. Each effect returns None for success and Some with the error for failure.

@seeforEach for iterating over elements and applying an effect.

@seeallWith for a data-last version of this function.

@example

// Title: Combining Effects in Tuples
import { Effect, Console } from "effect"
const tupleOfEffects = [
Effect.succeed(42).pipe(Effect.tap(Console.log)),
Effect.succeed("Hello").pipe(Effect.tap(Console.log))
] as const
// ┌─── Effect<[number, string], never, never>
// ▼
const resultsAsTuple = Effect.all(tupleOfEffects)
// Effect.runPromise(resultsAsTuple).then(console.log)
// Output:
// 42
// Hello
// [ 42, 'Hello' ]

@example

// Title: Combining Effects in Iterables import { Effect, Console } from "effect"

const iterableOfEffects: Iterable<Effect.Effect> = [1, 2, 3].map( (n) => Effect.succeed(n).pipe(Effect.tap(Console.log)) )

// ┌─── Effect<number[], never, never> // ▼ const resultsAsArray = Effect.all(iterableOfEffects)

// Effect.runPromise(resultsAsArray).then(console.log) // Output: // 1 // 2 // 3 // [ 1, 2, 3 ]

@example

// Title: Combining Effects in Structs import { Effect, Console } from "effect"

const structOfEffects = { a: Effect.succeed(42).pipe(Effect.tap(Console.log)), b: Effect.succeed("Hello").pipe(Effect.tap(Console.log)) }

// ┌─── Effect<{ a: number; b: string; }, never, never> // ▼ const resultsAsStruct = Effect.all(structOfEffects)

// Effect.runPromise(resultsAsStruct).then(console.log) // Output: // 42 // Hello // { a: 42, b: 'Hello' }

@example

// Title: Combining Effects in Records import { Effect, Console } from "effect"

const recordOfEffects: Record<string, Effect.Effect> = { key1: Effect.succeed(1).pipe(Effect.tap(Console.log)), key2: Effect.succeed(2).pipe(Effect.tap(Console.log)) }

// ┌─── Effect<{ [x: string]: number; }, never, never> // ▼ const resultsAsRecord = Effect.all(recordOfEffects)

// Effect.runPromise(resultsAsRecord).then(console.log) // Output: // 1 // 2 // { key1: 1, key2: 2 }

@example

// Title: Short-Circuiting Behavior import { Effect, Console } from "effect"

const program = Effect.all([ Effect.succeed("Task1").pipe(Effect.tap(Console.log)), Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), // Won't execute due to earlier failure Effect.succeed("Task3").pipe(Effect.tap(Console.log)) ])

// Effect.runPromiseExit(program).then(console.log) // Output: // Task1 // { // _id: 'Exit', // _tag: 'Failure', // cause: { _id: 'Cause', _tag: 'Fail', failure: 'Task2: Oh no!' } // }

@example

// Title: Collecting Results with mode: "either" import { Effect, Console } from "effect"

const effects = [ Effect.succeed("Task1").pipe(Effect.tap(Console.log)), Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), Effect.succeed("Task3").pipe(Effect.tap(Console.log)) ]

const program = Effect.all(effects, { mode: "either" })

// Effect.runPromiseExit(program).then(console.log) // Output: // Task1 // Task3 // { // _id: 'Exit', // _tag: 'Success', // value: [ // { _id: 'Either', _tag: 'Right', right: 'Task1' }, // { _id: 'Either', _tag: 'Left', left: 'Task2: Oh no!' }, // { _id: 'Either', _tag: 'Right', right: 'Task3' } // ] // }

@example

//Example: Collecting Results with mode: "validate" import { Effect, Console } from "effect"

const effects = [ Effect.succeed("Task1").pipe(Effect.tap(Console.log)), Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), Effect.succeed("Task3").pipe(Effect.tap(Console.log)) ]

const program = Effect.all(effects, { mode: "validate" })

// Effect.runPromiseExit(program).then((result) => console.log("%o", result)) // Output: // Task1 // Task3 // { // _id: 'Exit', // _tag: 'Failure', // cause: { // _id: 'Cause', // _tag: 'Fail', // failure: [ // { _id: 'Option', _tag: 'None' }, // { _id: 'Option', _tag: 'Some', value: 'Task2: Oh no!' }, // { _id: 'Option', _tag: 'None' } // ] // } // }

@since2.0.0

all
(
const tasks: Effect.Effect<void, never, never>[]
tasks
, {
concurrency: "unbounded"
concurrency
: "unbounded" })
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, 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: Effect.Effect<void, never, never>
program
)
/*
Output:
timestamp=... level=INFO fiber=#1 message="process: 1" elapsed=2011ms
timestamp=... level=INFO fiber=#2 message="process: 2" elapsed=2017ms
timestamp=... level=INFO fiber=#3 message="process: 3" elapsed=4020ms
timestamp=... level=INFO fiber=#4 message="process: 4" elapsed=6025ms
timestamp=... level=INFO fiber=#5 message="process: 5" elapsed=8034ms
*/