FiberMap
Manages fibers by key inside a scope.
A FiberMap<K, A, E> owns a map of running fibers, interrupts them when its
scope closes, and automatically removes each entry when the corresponding
fiber completes. Use it when a program needs to start, replace, join, or
interrupt background work by a stable key while keeping all fibers tied to
one scope.
Combinators
awaitEmpty
Waits for the FiberMap to be empty. This will wait for all currently running fibers to complete.
Signature
declare function awaitEmpty<K, A, E>(self: FiberMap<K, A, E>): Effect<void, E>Example
(Waiting for an empty map)
import { Effect, FiberMap } from "effect"
const program = Effect.gen(function*() { const map = yield* FiberMap.make<string>()
yield* FiberMap.run(map, "task1", Effect.yieldNow) yield* FiberMap.run(map, "task2", Effect.yieldNow)
// Wait for the map to be empty yield* FiberMap.awaitEmpty(map)
return yield* FiberMap.size(map)})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => 0Removes all fibers from the FiberMap, interrupting them.
Signature
declare function clear<K, A, E>(self: FiberMap<K, A, E>): Effect<void>Example
(Clearing all fibers)
import { Effect, FiberMap } from "effect"
const program = Effect.gen(function*() { const map = yield* FiberMap.make<string>()
// Add some fibers to the map yield* FiberMap.run(map, "task1", Effect.never) yield* FiberMap.run(map, "task2", Effect.never) yield* FiberMap.run(map, "task3", Effect.never)
const sizeBefore = yield* FiberMap.size(map)
// Clear all fibers (this will interrupt all of them) yield* FiberMap.clear(map)
return [sizeBefore, yield* FiberMap.size(map)]})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => [3, 0]Retrieves a fiber from the FiberMap effectfully.
Details
Returns an Option wrapped in Effect.
Signature
declare const get: { <K>(key: K): <A, E>(self: FiberMap<K, A, E>) => Effect<Option<Fiber<A, E>>>; <K, A, E>(self: FiberMap<K, A, E>, key: K): Effect<Option<Fiber<A, E>>>;}Example
(Retrieving a fiber)
import { Deferred, Effect, Fiber, FiberMap, Option } from "effect"
const program = Effect.gen(function*() { const map = yield* FiberMap.make<string>() const deferred = yield* Deferred.make<string>()
// Add a fiber to the map const fiber = yield* Effect.forkChild(Deferred.await(deferred)) yield* FiberMap.set(map, "greeting", fiber)
// Retrieve the fiber with error handling const retrieved = yield* FiberMap.get(map, "greeting") yield* Deferred.succeed(deferred, "Hello") const result = yield* Fiber.join(fiber) return Option.map(retrieved, () => result)})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => Option.some("Hello")Retrieves a fiber from the FiberMap synchronously.
When to use
Use when synchronous keyed lookup of a fiber in a FiberMap is needed and an
Option result is enough outside the Effect workflow.
Signature
declare const getUnsafe: { <K>(key: K): <A, E>(self: FiberMap<K, A, E>) => Option<Fiber<A, E>>; <K, A, E>(self: FiberMap<K, A, E>, key: K): Option<Fiber<A, E>>;}Example
(Retrieving a fiber unsafely)
import { Deferred, Effect, Fiber, FiberMap, Option } from "effect"
const program = Effect.gen(function*() { const map = yield* FiberMap.make<string>() const deferred = yield* Deferred.make<string>()
// Add a fiber to the map const fiber = yield* Effect.forkChild(Deferred.await(deferred)) FiberMap.setUnsafe(map, "greeting", fiber)
// Retrieve the fiber const retrieved = FiberMap.getUnsafe(map, "greeting") yield* Deferred.succeed(deferred, "Hello") const result = yield* Fiber.join(fiber) return Option.map(retrieved, () => result)})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => Option.some("Hello")Checks whether a key exists in the FiberMap.
This is the Effect-wrapped version of hasUnsafe.
Signature
declare const has: { <K>(key: K): <A, E>(self: FiberMap<K, A, E>) => Effect<boolean>; <K, A, E>(self: FiberMap<K, A, E>, key: K): Effect<boolean>;}Example
(Checking if a key exists)
import { Effect, FiberMap } from "effect"
const program = Effect.gen(function*() { const map = yield* FiberMap.make<string>()
// Add a fiber to the map yield* FiberMap.run(map, "task1", Effect.never)
// Check if keys exist using Effect return [yield* FiberMap.has(map, "task1"), yield* FiberMap.has(map, "task2")]})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => [true, false]Checks whether a key exists in the FiberMap.
Signature
declare const hasUnsafe: { <K>(key: K): <A, E>(self: FiberMap<K, A, E>) => boolean; <K, A, E>(self: FiberMap<K, A, E>, key: K): boolean;}Example
(Checking if a key exists unsafely)
import { Effect, FiberMap } from "effect"
const program = Effect.gen(function*() { const map = yield* FiberMap.make<string>()
// Add a fiber to the map yield* FiberMap.run(map, "task1", Effect.never)
// Check if keys exist return [FiberMap.hasUnsafe(map, "task1"), FiberMap.hasUnsafe(map, "task2")]})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => [true, false]Waits for the FiberMap to fail or close.
Details
The returned Effect fails with the first managed fiber failure that is not
ignored by the map's interruption rules. Normal successful completion
removes fibers from the map; use awaitEmpty to wait until the map has no
fibers.
Signature
declare function join<K, A, E>(self: FiberMap<K, A, E>): Effect<void, E>Example
(Joining failing fibers)
import { Effect, Exit, FiberMap } from "effect"
const program = Effect.gen(function*() { const map = yield* FiberMap.make() yield* FiberMap.set(map, "a", Effect.runFork(Effect.fail("error")))
// parent fiber will fail with "error" yield* FiberMap.join(map)})
const actual = await Effect.runPromise(Effect.exit(Effect.scoped(program)))actual // => Exit.fail("error")Removes a fiber from the FiberMap, interrupting it if it exists.
Signature
declare const remove: { <K>(key: K): <A, E>(self: FiberMap<K, A, E>) => Effect<void>; <K, A, E>(self: FiberMap<K, A, E>, key: K): Effect<void>;}Example
(Removing a fiber)
import { Effect, FiberMap } from "effect"
const program = Effect.gen(function*() { const map = yield* FiberMap.make<string>()
// Add some fibers to the map yield* FiberMap.run(map, "task1", Effect.never) yield* FiberMap.run(map, "task2", Effect.never)
const sizeBefore = yield* FiberMap.size(map)
// Remove a specific fiber (this will interrupt it) yield* FiberMap.remove(map, "task1")
return [sizeBefore, yield* FiberMap.size(map)]})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => [2, 1]Forks an Effect and stores the resulting fiber in the FiberMap under a key.
Details
When the fiber completes, it is removed from the map. If the key already has
a fiber, the previous fiber is interrupted unless onlyIfMissing is set.
Signature
declare const run: { <K, A, E>(self: FiberMap<K, A, E>, key: K, options?: { readonly onlyIfMissing?: boolean; readonly propagateInterruption?: boolean; readonly startImmediately?: boolean; }): <R, XE, XA>(effect: Effect<XA, XE, R>) => Effect<Fiber<XA, XE>, never, R>; <K, A, E, R, XE, XA>(self: FiberMap<K, A, E>, key: K, effect: Effect<XA, XE, R>, options?: { readonly onlyIfMissing?: boolean; readonly propagateInterruption?: boolean; readonly startImmediately?: boolean; }): Effect<Fiber<XA, XE>, never, R>;}Example
(Forking effects into a map)
import { Effect, Fiber, FiberMap } from "effect"
const program = Effect.gen(function*() { const map = yield* FiberMap.make<string>()
// Run effects and add the fibers to the map const fiber1 = yield* FiberMap.run(map, "task1", Effect.succeed("Hello")) const fiber2 = yield* FiberMap.run(map, "task2", Effect.succeed("World"))
// Join the fibers to get their successful values const result1 = yield* Fiber.join(fiber1) const result2 = yield* Fiber.join(fiber2) return [result1, result2, yield* FiberMap.size(map)]})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => ["Hello", "World", 0]Captures the current runtime and returns a function for forking effects into
an existing FiberMap.
Details
Each call stores the forked fiber under the supplied key. If that key already
has a fiber, the previous fiber is interrupted unless onlyIfMissing is set.
Signature
declare const runtime: <K, A, E>(self: FiberMap<K, A, E>) => <R = never>() => Effect.Effect<<XE extends E, XA extends A>(key: K, effect: Effect.Effect<XA, XE, R>, options?: Effect.RunOptions & { readonly onlyIfMissing?: boolean; readonly propagateInterruption?: boolean;}) => Fiber.Fiber<XA, XE>, never, R>Example
(Capturing a runtime)
import { Context, Effect, Fiber, FiberMap } from "effect"
class Users extends Context.Service<Users, { readonly getAll: Effect.Effect<Array<unknown>>}>()("Users") {}
const program = Effect.gen(function*() { const map = yield* FiberMap.make<string>() const run = yield* FiberMap.runtime(map)<Users>()
// run some effects and add the fibers to the map const fiberA = run("effect-a", Effect.andThen(Users, (_) => _.getAll)) const fiberB = run("effect-b", Effect.andThen(Users, (_) => _.getAll)) return [(yield* Fiber.join(fiberA)).length, (yield* Fiber.join(fiberB)).length]}).pipe( Effect.scoped // The fibers will be interrupted when the scope is closed)
const actual = await Effect.runPromise(Effect.provideService(program, Users, { getAll: Effect.succeed([])}))actual // => [0, 0]runtimePromise
Captures the current runtime and returns a function for running effects in
an existing FiberMap as Promises.
Details
Each call stores the forked fiber under the supplied key, interrupting any
previous fiber for that key unless onlyIfMissing is set. The Promise
resolves with the effect's success value or rejects with the squashed failure
cause.
Signature
declare function runtimePromise<K, A, E>(self: FiberMap<K, A, E>): <R = never>() => Effect<<XE, XA>(key: K, effect: Effect<XA, XE, R>, options?: RunOptions & { readonly onlyIfMissing?: boolean; readonly propagateInterruption?: boolean;}) => Promise<XA>, never, R>Example
(Running effects as promises)
import { Effect, FiberMap } from "effect"
const program = Effect.gen(function*() { const map = yield* FiberMap.make<string>() const runPromise = yield* FiberMap.runtimePromise(map)<never>()
// Create promises that will be backed by fibers in the map const promise1 = runPromise("task1", Effect.succeed("Hello")) const promise2 = runPromise("task2", Effect.succeed("World"))
// Convert promises back to Effects and await return [yield* Effect.promise(() => promise1), yield* Effect.promise(() => promise2)]})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => ["Hello", "World"]Adds a fiber to the FiberMap under a key.
Details
When the fiber completes, it is removed from the map. If the key already has
a fiber, that previous fiber is interrupted unless onlyIfMissing is set;
in that case the new fiber is interrupted and the existing entry is kept.
This is the Effect-wrapped version of setUnsafe.
Signature
declare const set: { <K, A, E, XE, XA>(key: K, fiber: Fiber<XA, XE>, options?: { readonly onlyIfMissing?: boolean; readonly propagateInterruption?: boolean; }): (self: FiberMap<K, A, E>) => Effect<void>; <K, A, E, XE, XA>(self: FiberMap<K, A, E>, key: K, fiber: Fiber<XA, XE>, options?: { readonly onlyIfMissing?: boolean; readonly propagateInterruption?: boolean; }): Effect<void>;}Example
(Adding a fiber)
import { Deferred, Effect, Fiber, FiberMap } from "effect"
const program = Effect.gen(function*() { const map = yield* FiberMap.make<string>() const deferred = yield* Deferred.make<string>()
// Create a fiber and add it to the map using Effect const fiber = yield* Effect.forkChild(Deferred.await(deferred)) yield* FiberMap.set(map, "greeting", fiber)
yield* Deferred.succeed(deferred, "Hello")
// Join the fiber to get its successful value return yield* Fiber.join(fiber)})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => "Hello"Adds a fiber to the FiberMap under a key using a synchronous, unsafe
mutation.
When to use
Use when an existing forked fiber must be installed under a key immediately and synchronous interruption of the replaced fiber is acceptable.
Details
When the fiber completes, it is removed from the map. If the key already has
a fiber, that previous fiber is interrupted unless onlyIfMissing is set;
in that case the new fiber is interrupted and the existing entry is kept.
Signature
declare const setUnsafe: { <K, A, E, XE, XA>(key: K, fiber: Fiber<XA, XE>, options?: { readonly onlyIfMissing?: boolean; readonly propagateInterruption?: boolean; }): (self: FiberMap<K, A, E>) => void; <K, A, E, XE, XA>(self: FiberMap<K, A, E>, key: K, fiber: Fiber<XA, XE>, options?: { readonly onlyIfMissing?: boolean; readonly propagateInterruption?: boolean; }): void;}Example
(Adding a fiber unsafely)
import { Deferred, Effect, Fiber, FiberMap } from "effect"
const program = Effect.gen(function*() { const map = yield* FiberMap.make<string>() const deferred = yield* Deferred.make<string>()
// Create a fiber and add it to the map const fiber = yield* Effect.forkChild(Deferred.await(deferred)) FiberMap.setUnsafe(map, "greeting", fiber)
yield* Deferred.succeed(deferred, "Hello")
// Join the fiber to get its successful value return yield* Fiber.join(fiber)})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => "Hello"Gets the number of fibers currently in the FiberMap.
Signature
declare function size<K, A, E>(self: FiberMap<K, A, E>): Effect<number>Example
(Checking the map size)
import { Effect, FiberMap } from "effect"
const program = Effect.gen(function*() { const map = yield* FiberMap.make<string>()
const sizeBefore = yield* FiberMap.size(map)
// Add some fibers yield* FiberMap.run(map, "task1", Effect.never) yield* FiberMap.run(map, "task2", Effect.never)
return [sizeBefore, yield* FiberMap.size(map)]})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => [0, 2]Constructors
Creates a scoped FiberMap for storing fibers by key.
Details
When the associated Scope is closed, all fibers in the map will be
interrupted. You can add fibers to the map using FiberMap.set or
FiberMap.run, and the fibers will be automatically removed from the
FiberMap when they complete.
Signature
declare function make<K, A = unknown, E = unknown>(): Effect<FiberMap<K, A, E>, never, Scope>Example
(Creating a scoped FiberMap)
import { Effect, FiberMap } from "effect"
const program = Effect.gen(function*() { const map = yield* FiberMap.make<string>()
// run some effects and add the fibers to the map yield* FiberMap.run(map, "fiber a", Effect.never) yield* FiberMap.run(map, "fiber b", Effect.never)
yield* Effect.yieldNow return yield* FiberMap.size(map)}).pipe( Effect.scoped // The fibers will be interrupted when the scope is closed)
const actual = await Effect.runPromise(program)actual // => 2makeRuntime
Creates a scoped run function that forks effects into a new FiberMap.
Details
Each call stores the forked fiber under the supplied key and returns that
fiber. If the key already has a fiber, the previous fiber is interrupted
unless onlyIfMissing is set. All managed fibers are interrupted when the
map's scope closes.
Signature
declare function makeRuntime<R, K, E = unknown, A = unknown>(): Effect<<XE, XA>(key: K, effect: Effect<XA, XE, R>, options?: RunOptions & { readonly onlyIfMissing?: boolean;}) => Fiber<XA, XE>, never, Scope | R>Example
(Creating a scoped runtime)
import { Effect, Fiber, FiberMap } from "effect"
const program = Effect.gen(function*() { const run = yield* FiberMap.makeRuntime<never, string>()
// Run effects and get back fibers const fiber1 = run("task1", Effect.succeed("Hello")) const fiber2 = run("task2", Effect.succeed("World"))
// Join the fibers to get their successful values return [yield* Fiber.join(fiber1), yield* Fiber.join(fiber2)]})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => ["Hello", "World"]makeRuntimePromise
Creates a scoped run function that forks effects into a new FiberMap and
returns a Promise for each effect result.
When to use
Use when keyed fibers must be managed in a scoped map while exposing their results through Promise-based APIs.
Details
Each call stores the fiber under the supplied key, interrupting any previous
fiber for that key unless onlyIfMissing is set. The returned Promise
resolves with the effect's success value or rejects with the squashed failure
cause.
Signature
declare function makeRuntimePromise<R, K, A = unknown, E = unknown>(): Effect<<XE, XA>(key: K, effect: Effect<XA, XE, R>, options?: RunOptions & { readonly onlyIfMissing?: boolean;}) => Promise<XA>, never, Scope | R>Example
(Creating a promise runtime)
import { Effect, FiberMap } from "effect"
const program = Effect.gen(function*() { const run = yield* FiberMap.makeRuntimePromise<never, string>()
// Run effects and get back promises const promise1 = run("task1", Effect.succeed("Hello")) const promise2 = run("task2", Effect.succeed("World"))
// Convert to Effect and await return [yield* Effect.promise(() => promise1), yield* Effect.promise(() => promise2)]})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => ["Hello", "World"]Guards
isFiberMap
Returns true if a value is a FiberMap.
Details
This is a type guard that checks for the FiberMap runtime marker.
Signature
declare function isFiberMap(u: unknown): u is FiberMap<unknown, unknown, unknown>Example
(Checking if a value is a FiberMap)
import { Effect, FiberMap } from "effect"
const program = Effect.gen(function*() { const map = yield* FiberMap.make<string>()
return [FiberMap.isFiberMap(map), FiberMap.isFiberMap({}), FiberMap.isFiberMap(null)]})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => [true, false, false]Models
A FiberMap is a collection of fibers, indexed by a key. When the associated Scope is closed, all fibers in the map will be interrupted. Fibers are automatically removed from the map when they complete.
Signature
interface FiberMap<in out K, out A = unknown, out E = unknown> extends Pipeable, Inspectable, "/home/runner/work/website/website/.effect-source-v4/packages/effect/src/Iterable"<[K, Fiber.Fiber<A, E>]> { readonly "~effect/FiberMap": "~effect/FiberMap"; readonly deferred: Deferred<void, unknown>; state: { readonly _tag: "Open"; readonly backing: MutableHashMap<K, Fiber<A, E>>; } | { readonly _tag: "Closed"; };}Example
(Managing fibers in a map)
import { Effect, FiberMap } from "effect"
// Create a FiberMap with string keysconst program = Effect.gen(function*() { const map = yield* FiberMap.make<string>()
// Add some fibers to the map yield* FiberMap.run(map, "task1", Effect.never) yield* FiberMap.run(map, "task2", Effect.never)
// Get the size of the map return yield* FiberMap.size(map)})
const actual = await Effect.runPromise(Effect.scoped(program))actual // => 2