Fiber Collections
Effect.forkChild is perfect for a fixed handful of fibers, but real services
spawn fibers dynamically — one per WebSocket connection, one per scheduled job,
one per in-flight subscription. You need somewhere to keep those handles so they
can be interrupted when the owning scope
closes, and so a fiber is forgotten once it finishes. That’s what the fiber
collections do:
FiberHandle— holds at most one fiber. Starting a new one interrupts the previous. Great for “latest wins” work like a debounced refresh.FiberMap— holds fibers keyed by some value. Ideal for one fiber per entity (connection id, user id, job id).FiberSet— holds an unkeyed set of fibers. Use it for a pool of workers you start and forget.
All three are created within a Scope. When that scope closes, every fiber in
the collection is interrupted automatically — so they fit naturally inside a
service’s layer, and you never leak a background fiber.
import { Context, Effect, FiberMap, Layer } from "effect"
// A service that runs one background subscription fiber per topic.export class Subscriptions extends Context.Service<Subscriptions, { subscribe(topic: string): Effect.Effect<void> unsubscribe(topic: string): Effect.Effect<void>}>()("app/Subscriptions") { static readonly layer = Layer.effect( Subscriptions, Effect.gen(function*() { // The FiberMap is tied to this layer's Scope: when the layer is // released, every subscription fiber is interrupted for us. const fibers = yield* FiberMap.make<string>()
const subscribe = Effect.fn("Subscriptions.subscribe")( function*(topic: string) { // `run` forks the effect and stores it under `topic`. If a fiber // already exists for that key it is interrupted and replaced. yield* FiberMap.run( fibers, topic, Effect.forever( Effect.log(`polling ${topic}`).pipe(Effect.delay("1 second")) ) ) } )
const unsubscribe = Effect.fn("Subscriptions.unsubscribe")( function*(topic: string) { // Interrupt and drop just this key's fiber. yield* FiberMap.remove(fibers, topic) } )
return Subscriptions.of({ subscribe, unsubscribe }) }) )}Why not a plain array of fibers?
Section titled “Why not a plain array of fibers?”You could keep fibers in a Set yourself, but you’d have to remove each one
when it completes, interrupt every survivor on shutdown, and handle the race
between a fiber finishing and you removing it. The fiber collections do all of
this correctly:
- a fiber is removed automatically when it terminates, so the collection never holds dead handles;
- closing the owning scope interrupts all remaining fibers;
- failures can be propagated to the collection so one bad fiber can surface an error instead of failing silently.
FiberHandle — at most one fiber
Section titled “FiberHandle — at most one fiber”A FiberHandle stores a single fiber. FiberHandle.run forks an effect into it;
if it already holds a running fiber, that one is interrupted first. This is the
“only the latest matters” pattern — re-running a search as the user types, or
restarting a watcher when config changes.
import { Effect, FiberHandle } from "effect"
const program = Effect.scoped( Effect.gen(function*() { const handle = yield* FiberHandle.make<string>()
// Start a task... yield* FiberHandle.run(handle, Effect.succeed("v1").pipe(Effect.delay("1 second")))
// ...then start a newer one. The previous fiber is interrupted. yield* FiberHandle.run(handle, Effect.succeed("v2"))
// `join` waits for the current fiber and re-raises its failure, if any. yield* FiberHandle.join(handle) }))Pass { onlyIfMissing: true } to run if you’d rather keep the existing fiber
and skip starting a new one when one is already present.
FiberMap — one fiber per key
Section titled “FiberMap — one fiber per key”A FiberMap<K> indexes fibers by a key. FiberMap.run(map, key, effect) forks
under that key (replacing any existing fiber for it), FiberMap.remove(map, key)
interrupts and drops one, and FiberMap.has / FiberMap.size let you inspect
the collection. This is the workhorse for “one background fiber per entity” — see
the Subscriptions service above.
FiberSet — an unkeyed pool
Section titled “FiberSet — an unkeyed pool”A FiberSet is the simplest of the three: an unkeyed bag of fibers. Use it to
fork a fluctuating number of tasks and have them all cleaned up together.
import { Effect, FiberSet } from "effect"
const program = Effect.scoped( Effect.gen(function*() { const set = yield* FiberSet.make<void>()
// Fork some work into the set; each fiber removes itself when it finishes. yield* FiberSet.run(set, Effect.log("job a").pipe(Effect.delay("100 millis"))) yield* FiberSet.run(set, Effect.log("job b").pipe(Effect.delay("200 millis")))
// Wait until every fiber in the set has completed. yield* FiberSet.awaitEmpty(set) }))// Leaving the scope would interrupt any fibers still running.Shared patterns
Section titled “Shared patterns”All three modules speak the same vocabulary, so once you learn one the others follow:
- Scoped construction.
makeis anEffectthat requires aScope. It acquires the collection withacquireRelease, and its finalizer interrupts every fiber still inside when the scope closes. Run it insideEffect.scoped, aLayer, or any other scope owner. - Forking helpers.
runforks an effect into the collection inheriting the current fiber’s services.runtimeandruntimePromiseinstead capture the surrounding services once and hand back a plain (non-Effect) function you can call from callbacks, event handlers, orPromise-based glue. ThemakeRuntime*constructors fusemake+ the captured runner in one step. - Tracking & replacement.
set/addstore an already-forked fiber.FiberHandle.setreplaces (and interrupts) the held fiber;FiberMap.setreplaces the fiber for that key;FiberSet.addsimply tracks one more fiber. - Self-removal. A tracked fiber removes itself from the collection when it completes, so the collection never accumulates dead handles.
joinvsawaitEmpty.joinwaits for the collection’s first non-ignored failure (interrupts are ignored by default; opt in withpropagateInterruption: true).awaitEmptywaits until all currently tracked fibers have finished, regardless of outcome.Unsafevariants.setUnsafe/addUnsafe/getUnsafe/hasUnsafemutate or read synchronously, outside ofEffect. Use them only when you already control the surrounding execution context.
Choosing between them
Section titled “Choosing between them”| Need | Use |
|---|---|
| Only the most recent task should run | FiberHandle |
| One fiber per id / entity, addressable later | FiberMap |
| A pool of interchangeable background tasks | FiberSet |
A fixed, known number of fibers in a gen block | plain forkChild + Fiber.join |
| Map a collection with a parallelism cap | the concurrency option |
FiberHandle reference
Section titled “FiberHandle reference”A FiberHandle<A, E> holds at most one Fiber<A, E>. Installing a new fiber
interrupts the previous one (unless onlyIfMissing is set), and a completed
fiber removes itself so the handle can be reused.
Creates a scoped FiberHandle; the held fiber is interrupted when the scope
closes.
import { Effect, FiberHandle } from "effect"
Effect.gen(function*() { const handle = yield* FiberHandle.make<string>() yield* FiberHandle.run(handle, Effect.succeed("hi"))}).pipe(Effect.scoped)makeRuntime
Section titled “makeRuntime”Creates a scoped handle and immediately returns a captured run function that
forks effects into it, returning the forked Fiber.
import { Effect, Fiber, FiberHandle } from "effect"
Effect.gen(function*() { const run = yield* FiberHandle.makeRuntime<never>()
const fiberA = run(Effect.succeed("first")) const fiberB = run(Effect.succeed("second")) // interrupts fiberA
yield* Fiber.await(fiberB) // => Exit.succeed("second")}).pipe(Effect.scoped)makeRuntimePromise
Section titled “makeRuntimePromise”Like makeRuntime, but the returned runner resolves a Promise with the
effect’s success value (or rejects with the squashed cause).
import { Effect, FiberHandle } from "effect"
Effect.gen(function*() { const run = yield* FiberHandle.makeRuntimePromise()
const result = yield* Effect.promise(() => run(Effect.succeed("hello"))) console.log(result) // => "hello"}).pipe(Effect.scoped)Stores an already-forked fiber in the handle, interrupting the previously held
fiber unless onlyIfMissing is set. Returns an Effect.
import { Effect, Fiber, FiberHandle } from "effect"
Effect.gen(function*() { const handle = yield* FiberHandle.make<string>() const fiber = Effect.runFork(Effect.succeed("hello"))
yield* FiberHandle.set(handle, fiber) console.log(yield* Fiber.await(fiber)) // => Exit.succeed("hello")}).pipe(Effect.scoped)setUnsafe
Section titled “setUnsafe”Synchronous, non-Effect version of set. Use when you already control the
execution context.
import { Effect, FiberHandle } from "effect"
Effect.gen(function*() { const handle = yield* FiberHandle.make<string>() const fiber = Effect.runFork(Effect.succeed("hello"))
FiberHandle.setUnsafe(handle, fiber) // mutates synchronously, returns void}).pipe(Effect.scoped)Returns the current fiber as an Option, wrapped in Effect.
import { Effect, FiberHandle } from "effect"
Effect.gen(function*() { const handle = yield* FiberHandle.make<string>() yield* FiberHandle.run(handle, Effect.never)
const current = yield* FiberHandle.get(handle) console.log(current._tag) // => "Some"}).pipe(Effect.scoped)getUnsafe
Section titled “getUnsafe”Synchronous version of get: returns Option<Fiber<A, E>> directly.
import { Effect, FiberHandle } from "effect"
Effect.gen(function*() { const handle = yield* FiberHandle.make<string>()
console.log(FiberHandle.getUnsafe(handle)._tag) // => "None"}).pipe(Effect.scoped)Interrupts the currently held fiber (if any) and leaves the handle empty and reusable.
import { Effect, FiberHandle } from "effect"
Effect.gen(function*() { const handle = yield* FiberHandle.make() yield* FiberHandle.run(handle, Effect.never)
yield* FiberHandle.clear(handle) console.log(FiberHandle.getUnsafe(handle)._tag) // => "None"}).pipe(Effect.scoped)Forks an effect into the handle (inheriting the current fiber’s services) and
returns the forked Fiber. Running a new effect interrupts the previous fiber
unless onlyIfMissing is set.
import { Effect, Fiber, FiberHandle } from "effect"
Effect.gen(function*() { const handle = yield* FiberHandle.make<string>()
const f1 = yield* FiberHandle.run(handle, Effect.succeed("hello")) console.log(yield* Fiber.await(f1)) // => Exit.succeed("hello")
// Skip if a fiber is already present: yield* FiberHandle.run(handle, Effect.succeed("world"), { onlyIfMissing: true })}).pipe(Effect.scoped)runtime
Section titled “runtime”Captures the surrounding services and returns a plain function for forking effects into an existing handle. Handy when forking from callbacks.
import { Context, Effect, FiberHandle } from "effect"
interface Users {}const Users = Context.Service<Users, { readonly getAll: Effect.Effect<ReadonlyArray<unknown>>}>("Users")
Effect.gen(function*() { const handle = yield* FiberHandle.make() const run = yield* FiberHandle.runtime(handle)<Users>()
run(Effect.flatMap(Users, (_) => _.getAll)) run(Effect.flatMap(Users, (_) => _.getAll)) // interrupts the previous fiber}).pipe(Effect.scoped)runtimePromise
Section titled “runtimePromise”Captures the runtime and returns a runner that yields a Promise per effect.
import { Effect, FiberHandle } from "effect"
Effect.gen(function*() { const handle = yield* FiberHandle.make() const run = yield* FiberHandle.runtimePromise(handle)<never>()
const result = yield* Effect.promise(() => run(Effect.succeed("hello"))) console.log(result) // => "hello"}).pipe(Effect.scoped)Waits for the handle to fail or close, re-raising the first non-ignored failure. Successful completion of the held fiber only empties the handle.
import { Effect, FiberHandle } from "effect"
Effect.gen(function*() { const handle = yield* FiberHandle.make() yield* FiberHandle.set(handle, Effect.runFork(Effect.fail("boom")))
yield* FiberHandle.join(handle) // => fails with "boom"}).pipe(Effect.scoped)awaitEmpty
Section titled “awaitEmpty”Waits for the fiber that is current when the call starts to complete (success or failure), then resolves.
import { Effect, FiberHandle } from "effect"
Effect.gen(function*() { const handle = yield* FiberHandle.make() yield* FiberHandle.run(handle, Effect.sleep("100 millis"))
yield* FiberHandle.awaitEmpty(handle) console.log("done") // => "done"}).pipe(Effect.scoped)isFiberHandle
Section titled “isFiberHandle”Type guard that returns true for FiberHandle values.
import { Effect, FiberHandle } from "effect"
Effect.gen(function*() { const handle = yield* FiberHandle.make() console.log(FiberHandle.isFiberHandle(handle)) // => true console.log(FiberHandle.isFiberHandle("nope")) // => false}).pipe(Effect.scoped)interface FiberHandle
Section titled “interface FiberHandle”FiberHandle<out A = unknown, out E = unknown> is Pipeable and Inspectable.
Its state is either { _tag: "Open", fiber: Fiber<A, E> | undefined } or
{ _tag: "Closed" }; a deferred field backs join. Type parameters constrain
what fibers the handle accepts: A is the success type, E the error type.
FiberMap reference
Section titled “FiberMap reference”A FiberMap<K, A, E> is a keyed registry of fibers. Adding under an existing key
interrupts the previous fiber for that key (unless onlyIfMissing), completed
fibers remove themselves, and closing the scope interrupts everything.
Creates a scoped FiberMap; all entries are interrupted when the scope closes.
import { Effect, FiberMap } from "effect"
Effect.gen(function*() { const map = yield* FiberMap.make<string>() yield* FiberMap.run(map, "a", Effect.never)}).pipe(Effect.scoped)makeRuntime
Section titled “makeRuntime”Creates a scoped map and returns a captured (key, effect, options?) => Fiber
runner in one step.
import { Effect, Fiber, FiberMap } from "effect"
Effect.gen(function*() { const run = yield* FiberMap.makeRuntime<never, string>()
const f1 = run("task1", Effect.succeed("Hello")) const f2 = run("task2", Effect.succeed("World"))
console.log(yield* Fiber.join(f1), yield* Fiber.join(f2)) // => "Hello" "World"}).pipe(Effect.scoped)makeRuntimePromise
Section titled “makeRuntimePromise”Like makeRuntime, but each call returns a Promise.
import { Effect, FiberMap } from "effect"
Effect.gen(function*() { const run = yield* FiberMap.makeRuntimePromise<never, string>()
const result = yield* Effect.promise(() => run("task1", Effect.succeed("Hello"))) console.log(result) // => "Hello"}).pipe(Effect.scoped)Stores an already-forked fiber under a key, interrupting the previous fiber for
that key unless onlyIfMissing is set.
import { Effect, Fiber, FiberMap } from "effect"
Effect.gen(function*() { const map = yield* FiberMap.make<string>() const fiber = yield* Effect.forkChild(Effect.succeed("Hello"))
yield* FiberMap.set(map, "greeting", fiber) console.log(yield* Fiber.join(fiber)) // => "Hello"}).pipe(Effect.scoped)setUnsafe
Section titled “setUnsafe”Synchronous, non-Effect version of set.
import { Effect, FiberMap } from "effect"
Effect.gen(function*() { const map = yield* FiberMap.make<string>() const fiber = Effect.runFork(Effect.succeed("Hello"))
FiberMap.setUnsafe(map, "greeting", fiber) // returns void}).pipe(Effect.scoped)Returns the fiber for a key as Option, wrapped in Effect.
import { Effect, FiberMap } from "effect"
Effect.gen(function*() { const map = yield* FiberMap.make<string>() yield* FiberMap.run(map, "a", Effect.never)
const fiber = yield* FiberMap.get(map, "a") console.log(fiber._tag) // => "Some"}).pipe(Effect.scoped)getUnsafe
Section titled “getUnsafe”Synchronous version of get.
import { Effect, FiberMap } from "effect"
Effect.gen(function*() { const map = yield* FiberMap.make<string>() console.log(FiberMap.getUnsafe(map, "missing")._tag) // => "None"}).pipe(Effect.scoped)Returns whether a key currently has a fiber, wrapped in Effect.
import { Effect, FiberMap } from "effect"
Effect.gen(function*() { const map = yield* FiberMap.make<string>() yield* FiberMap.run(map, "task1", Effect.never)
console.log(yield* FiberMap.has(map, "task1")) // => true console.log(yield* FiberMap.has(map, "task2")) // => false}).pipe(Effect.scoped)hasUnsafe
Section titled “hasUnsafe”Synchronous version of has.
import { Effect, FiberMap } from "effect"
Effect.gen(function*() { const map = yield* FiberMap.make<string>() yield* FiberMap.run(map, "task1", Effect.never)
console.log(FiberMap.hasUnsafe(map, "task1")) // => true}).pipe(Effect.scoped)remove
Section titled “remove”Interrupts and removes the fiber for a single key.
import { Effect, FiberMap } from "effect"
Effect.gen(function*() { const map = yield* FiberMap.make<string>() yield* FiberMap.run(map, "task1", Effect.never) yield* FiberMap.run(map, "task2", Effect.never)
yield* FiberMap.remove(map, "task1") console.log(yield* FiberMap.size(map)) // => 1}).pipe(Effect.scoped)Interrupts every fiber in the map but keeps the map open and reusable.
import { Effect, FiberMap } from "effect"
Effect.gen(function*() { const map = yield* FiberMap.make<string>() yield* FiberMap.run(map, "a", Effect.never) yield* FiberMap.run(map, "b", Effect.never)
yield* FiberMap.clear(map) console.log(yield* FiberMap.size(map)) // => 0}).pipe(Effect.scoped)Forks an effect into the map under a key (inheriting current services) and
returns the forked Fiber, replacing any existing fiber for that key unless
onlyIfMissing is set.
import { Effect, Fiber, FiberMap } from "effect"
Effect.gen(function*() { const map = yield* FiberMap.make<string>()
const f1 = yield* FiberMap.run(map, "task1", Effect.succeed("Hello")) console.log(yield* Fiber.join(f1)) // => "Hello" console.log(yield* FiberMap.size(map)) // => 0 (removed on completion)}).pipe(Effect.scoped)runtime
Section titled “runtime”Captures the surrounding services and returns a plain
(key, effect, options?) => Fiber runner for an existing map.
import { Context, Effect, FiberMap } from "effect"
interface Users {}const Users = Context.Service<Users, { readonly getAll: Effect.Effect<ReadonlyArray<unknown>>}>("Users")
Effect.gen(function*() { const map = yield* FiberMap.make<string>() const run = yield* FiberMap.runtime(map)<Users>()
run("a", Effect.flatMap(Users, (_) => _.getAll)) run("b", Effect.flatMap(Users, (_) => _.getAll))}).pipe(Effect.scoped)runtimePromise
Section titled “runtimePromise”Captures the runtime and returns a runner that yields a Promise per effect.
import { Effect, FiberMap } from "effect"
Effect.gen(function*() { const map = yield* FiberMap.make<string>() const run = yield* FiberMap.runtimePromise(map)<never>()
const result = yield* Effect.promise(() => run("task1", Effect.succeed("Hello"))) console.log(result) // => "Hello"}).pipe(Effect.scoped)Returns the number of fibers currently in the map.
import { Effect, FiberMap } from "effect"
Effect.gen(function*() { const map = yield* FiberMap.make<string>() yield* FiberMap.run(map, "a", Effect.never) yield* FiberMap.run(map, "b", Effect.never)
console.log(yield* FiberMap.size(map)) // => 2}).pipe(Effect.scoped)Waits for the map to fail or close, re-raising the first non-ignored failure.
import { Effect, FiberMap } from "effect"
Effect.gen(function*() { const map = yield* FiberMap.make() yield* FiberMap.set(map, "a", Effect.runFork(Effect.fail("boom")))
yield* FiberMap.join(map) // => fails with "boom"}).pipe(Effect.scoped)awaitEmpty
Section titled “awaitEmpty”Waits until the map has no fibers — i.e. all currently tracked fibers have completed.
import { Effect, FiberMap } from "effect"
Effect.gen(function*() { const map = yield* FiberMap.make<string>() yield* FiberMap.run(map, "a", Effect.sleep("100 millis")) yield* FiberMap.run(map, "b", Effect.sleep("200 millis"))
yield* FiberMap.awaitEmpty(map) console.log(yield* FiberMap.size(map)) // => 0}).pipe(Effect.scoped)isFiberMap
Section titled “isFiberMap”Type guard that returns true for FiberMap values.
import { Effect, FiberMap } from "effect"
Effect.gen(function*() { const map = yield* FiberMap.make<string>() console.log(FiberMap.isFiberMap(map)) // => true console.log(FiberMap.isFiberMap({})) // => false}).pipe(Effect.scoped)interface FiberMap
Section titled “interface FiberMap”FiberMap<in out K, out A = unknown, out E = unknown> is Pipeable,
Inspectable, and Iterable<[K, Fiber<A, E>]>. Its state is either
{ _tag: "Open", backing: MutableHashMap<K, Fiber<A, E>> } or
{ _tag: "Closed" }. K is the key type, A/E the fibers’ success/error
types.
FiberSet reference
Section titled “FiberSet reference”A FiberSet<A, E> tracks an unkeyed set of fibers. Completed fibers are removed
automatically, and closing the scope (or calling clear) interrupts the rest.
Creates a scoped FiberSet; all members are interrupted when the scope closes.
import { Effect, FiberSet } from "effect"
Effect.gen(function*() { const set = yield* FiberSet.make() yield* FiberSet.run(set, Effect.never)}).pipe(Effect.scoped)makeRuntime
Section titled “makeRuntime”Creates a scoped set and returns a captured (effect, options?) => Fiber runner.
import { Effect, Fiber, FiberSet } from "effect"
Effect.gen(function*() { const run = yield* FiberSet.makeRuntime()
const fiber = run(Effect.succeed("hello")) console.log(yield* Fiber.await(fiber)) // => Exit.succeed("hello")}).pipe(Effect.scoped)makeRuntimePromise
Section titled “makeRuntimePromise”Like makeRuntime, but each call returns a Promise.
import { Effect, FiberSet } from "effect"
Effect.gen(function*() { const run = yield* FiberSet.makeRuntimePromise()
const result = yield* Effect.promise(() => run(Effect.succeed("hello"))) console.log(result) // => "hello"}).pipe(Effect.scoped)Adds an already-forked fiber to the set; it removes itself on completion.
import { Effect, FiberSet } from "effect"
Effect.gen(function*() { const set = yield* FiberSet.make() const fiber = yield* Effect.forkChild(Effect.succeed("hello"))
yield* FiberSet.add(set, fiber) console.log(yield* FiberSet.size(set)) // => 1}).pipe(Effect.scoped)addUnsafe
Section titled “addUnsafe”Synchronous, non-Effect version of add.
import { Effect, FiberSet } from "effect"
Effect.gen(function*() { const set = yield* FiberSet.make() const fiber = Effect.runFork(Effect.never)
FiberSet.addUnsafe(set, fiber) // returns void console.log(yield* FiberSet.size(set)) // => 1}).pipe(Effect.scoped)Interrupts every fiber in the set but keeps the set open and reusable.
import { Effect, FiberSet } from "effect"
Effect.gen(function*() { const set = yield* FiberSet.make() yield* FiberSet.run(set, Effect.never) yield* FiberSet.run(set, Effect.never)
yield* FiberSet.clear(set) console.log(yield* FiberSet.size(set)) // => 0}).pipe(Effect.scoped)Forks an effect into the set (inheriting current services) and returns the
forked Fiber.
import { Effect, Fiber, FiberSet } from "effect"
Effect.gen(function*() { const set = yield* FiberSet.make()
const fiber = yield* FiberSet.run(set, Effect.succeed("hello")) console.log(yield* Fiber.await(fiber)) // => Exit.succeed("hello")}).pipe(Effect.scoped)runtime
Section titled “runtime”Captures the surrounding services and returns a plain (effect, options?) => Fiber
runner for an existing set.
import { Context, Effect, FiberSet } from "effect"
interface Users {}const Users = Context.Service<Users, { readonly getAll: Effect.Effect<ReadonlyArray<unknown>>}>("Users")
Effect.gen(function*() { const set = yield* FiberSet.make() const run = yield* FiberSet.runtime(set)<Users>()
run(Effect.flatMap(Users, (_) => _.getAll))}).pipe(Effect.scoped)runtimePromise
Section titled “runtimePromise”Captures the runtime and returns a runner that yields a Promise per effect.
import { Effect, FiberSet } from "effect"
Effect.gen(function*() { const set = yield* FiberSet.make() const run = yield* FiberSet.runtimePromise(set)()
const result = yield* Effect.promise(() => run(Effect.succeed("hello"))) console.log(result) // => "hello"}).pipe(Effect.scoped)Returns the number of fibers currently in the set.
import { Effect, FiberSet } from "effect"
Effect.gen(function*() { const set = yield* FiberSet.make() yield* FiberSet.run(set, Effect.never) yield* FiberSet.run(set, Effect.never)
console.log(yield* FiberSet.size(set)) // => 2}).pipe(Effect.scoped)Waits for the set to fail, re-raising the first non-ignored failure.
import { Effect, FiberSet } from "effect"
Effect.gen(function*() { const set = yield* FiberSet.make() yield* FiberSet.add(set, Effect.runFork(Effect.fail("boom")))
yield* FiberSet.join(set) // => fails with "boom"}).pipe(Effect.scoped)awaitEmpty
Section titled “awaitEmpty”Waits until the set is empty — all currently tracked fibers have completed.
import { Effect, FiberSet } from "effect"
Effect.gen(function*() { const set = yield* FiberSet.make() yield* FiberSet.run(set, Effect.sleep("100 millis")) yield* FiberSet.run(set, Effect.sleep("200 millis"))
yield* FiberSet.awaitEmpty(set) console.log(yield* FiberSet.size(set)) // => 0}).pipe(Effect.scoped)isFiberSet
Section titled “isFiberSet”Type guard that returns true for FiberSet values.
import { Effect, FiberSet } from "effect"
Effect.gen(function*() { const set = yield* FiberSet.make() console.log(FiberSet.isFiberSet(set)) // => true console.log(FiberSet.isFiberSet({})) // => false}).pipe(Effect.scoped)interface FiberSet
Section titled “interface FiberSet”FiberSet<out A = unknown, out E = unknown> is Pipeable, Inspectable, and
Iterable<Fiber<A, E>>. Its state is either
{ _tag: "Open", backing: Set<Fiber<A, E>> } or { _tag: "Closed" }. A/E
constrain the success/error types of the fibers it accepts.