Supervisor
A Supervisor<A>
is a utility for managing fibers in Effect, allowing you to track their lifecycle (creation and termination) and producing a value of type A
that reflects this supervision. Supervisors are useful when you need insight into or control over the behavior of fibers within your application.
To create a supervisor, you can use the Supervisor.track
function. This generates a new supervisor that keeps track of its child fibers, maintaining them in a set. This allows you to observe and monitor their status during execution.
You can supervise an effect by using the Effect.supervised
function. This function takes a supervisor as an argument and returns an effect where all child fibers forked within it are supervised by the provided supervisor. This enables you to capture detailed information about these child fibers, such as their status, through the supervisor.
Example (Monitoring Fiber Count)
In this example, we’ll periodically monitor the number of fibers running in the application using a supervisor. The program calculates a Fibonacci number, spawning multiple fibers in the process, while a separate monitor tracks the fiber count.
1import { import Effect
Effect, import Supervisor
Supervisor, import Schedule
Schedule, import Fiber
Fiber, import FiberStatus
FiberStatus } from "effect"2
3// Main program that monitors fibers while calculating a Fibonacci number4const const program: Effect.Effect<void, never, never>
program = import Effect
Effect.const gen: <YieldWrap<Effect.Effect<Supervisor.Supervisor<Fiber.RuntimeFiber<any, any>[]>, never, never>> | YieldWrap<Effect.Effect<Fiber.RuntimeFiber<number, never>, never, never>> | YieldWrap<...>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {5 // Create a supervisor to track child fibers6 const const supervisor: Supervisor.Supervisor<Fiber.RuntimeFiber<any, any>[]>
supervisor = yield* import Supervisor
Supervisor.const track: Effect.Effect<Supervisor.Supervisor<Fiber.RuntimeFiber<any, any>[]>, never, never>
Creates a new supervisor that tracks children in a set.
track7
8 // Start a Fibonacci calculation, supervised by the supervisor9 const const fibFiber: Fiber.RuntimeFiber<number, never>
fibFiber = yield* const fib: (n: number) => Effect.Effect<number>
fib(20).(method) Pipeable.pipe<Effect.Effect<number, never, never>, Effect.Effect<number, never, never>, Effect.Effect<Fiber.RuntimeFiber<number, never>, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe(10 import Effect
Effect.const supervised: <Fiber.RuntimeFiber<any, any>[]>(supervisor: Supervisor.Supervisor<Fiber.RuntimeFiber<any, any>[]>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)
Returns an effect with the behavior of this one, but where all child fibers
forked in the effect are reported to the specified supervisor.
supervised(const supervisor: Supervisor.Supervisor<Fiber.RuntimeFiber<any, any>[]>
supervisor),11 // Fork the Fibonacci effect into a fiber12 import Effect
Effect.const fork: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Fiber.RuntimeFiber<A, E>, never, R>
Returns an effect that forks this effect into its own separate fiber,
returning the fiber immediately, without waiting for it to begin executing
the effect.
You can use the `fork` method whenever you want to execute an effect in a
new fiber, concurrently and without "blocking" the fiber executing other
effects. Using fibers can be tricky, so instead of using this method
directly, consider other higher-level methods, such as `raceWith`,
`zipPar`, and so forth.
The fiber returned by this method has methods to interrupt the fiber and to
wait for it to finish executing the effect. See `Fiber` for more
information.
Whenever you use this method to launch a new fiber, the new fiber is
attached to the parent fiber's scope. This means when the parent fiber
terminates, the child fiber will be terminated as well, ensuring that no
fibers leak. This behavior is called "auto supervision", and if this
behavior is not desired, you may use the `forkDaemon` or `forkIn` methods.
fork13 )14
15 // Define a schedule to periodically monitor the fiber count every 500ms16 const const policy: Schedule.Schedule<number, unknown, never>
policy = import Schedule
Schedule.const spaced: (duration: DurationInput) => Schedule.Schedule<number>
Returns a schedule that recurs continuously, each repetition spaced the
specified duration from the last run.
spaced("500 millis").(method) Pipeable.pipe<Schedule.Schedule<number, unknown, never>, Schedule.Schedule<number, unknown, never>>(this: Schedule.Schedule<...>, ab: (_: Schedule.Schedule<number, unknown, never>) => Schedule.Schedule<number, unknown, never>): Schedule.Schedule<...> (+21 overloads)
pipe(17 import Schedule
Schedule.const whileInputEffect: <unknown, never>(f: (input: unknown) => Effect.Effect<boolean, never, never>) => <Out, R>(self: Schedule.Schedule<Out, unknown, R>) => Schedule.Schedule<Out, unknown, R> (+1 overload)
Returns a new schedule that continues for as long as the specified effectful
predicate on the input evaluates to true.
whileInputEffect(((parameter) _: unknown
_) =>18 import Fiber
Fiber.const status: <number, never>(self: Fiber.RuntimeFiber<number, never>) => Effect.Effect<FiberStatus.FiberStatus>
Returns the `FiberStatus` of a `RuntimeFiber`.
status(const fibFiber: Fiber.RuntimeFiber<number, never>
fibFiber).(method) Pipeable.pipe<Effect.Effect<FiberStatus.FiberStatus, never, never>, Effect.Effect<boolean, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<FiberStatus.FiberStatus, never, never>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe(19 // Continue while the Fibonacci fiber is not done20 import Effect
Effect.const andThen: <FiberStatus.FiberStatus, boolean>(f: (a: FiberStatus.FiberStatus) => boolean) => <E, R>(self: Effect.Effect<FiberStatus.FiberStatus, E, R>) => Effect.Effect<...> (+3 overloads)
Executes a sequence of two actions, typically two `Effect`s, where the second action can depend on the result of the first action.
The `that` action can take various forms:
- a value
- a function returning a value
- a promise
- a function returning a promise
- an effect
- a function returning an effect
andThen(((parameter) status: FiberStatus.FiberStatus
status) => (parameter) status: FiberStatus.FiberStatus
status !== import FiberStatus
FiberStatus.const done: FiberStatus.FiberStatus
done)21 )22 )23 )24
25 // Start monitoring the fibers, using the supervisor to track the count26 const const monitorFiber: Fiber.RuntimeFiber<number, never>
monitorFiber = yield* const monitorFibers: (supervisor: Supervisor.Supervisor<Array<Fiber.RuntimeFiber<any, any>>>) => Effect.Effect<void>
monitorFibers(const supervisor: Supervisor.Supervisor<Fiber.RuntimeFiber<any, any>[]>
supervisor).(method) Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<number, never, never>, Effect.Effect<Fiber.RuntimeFiber<number, never>, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe(27 // Repeat the monitoring according to the schedule28 import Effect
Effect.const repeat: <number, unknown, never>(schedule: Schedule.Schedule<number, unknown, never>) => <E, R>(self: Effect.Effect<unknown, E, R>) => Effect.Effect<number, E, R> (+3 overloads)
The `repeat` function returns a new effect that repeats the given effect
according to a specified schedule or until the first failure. The scheduled
recurrences are in addition to the initial execution, so `Effect.repeat(action,
Schedule.once)` executes `action` once initially, and if it succeeds, repeats it
an additional time.
repeat(const policy: Schedule.Schedule<number, unknown, never>
policy),29 // Fork the monitoring into its own fiber30 import Effect
Effect.const fork: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Fiber.RuntimeFiber<A, E>, never, R>
Returns an effect that forks this effect into its own separate fiber,
returning the fiber immediately, without waiting for it to begin executing
the effect.
You can use the `fork` method whenever you want to execute an effect in a
new fiber, concurrently and without "blocking" the fiber executing other
effects. Using fibers can be tricky, so instead of using this method
directly, consider other higher-level methods, such as `raceWith`,
`zipPar`, and so forth.
The fiber returned by this method has methods to interrupt the fiber and to
wait for it to finish executing the effect. See `Fiber` for more
information.
Whenever you use this method to launch a new fiber, the new fiber is
attached to the parent fiber's scope. This means when the parent fiber
terminates, the child fiber will be terminated as well, ensuring that no
fibers leak. This behavior is called "auto supervision", and if this
behavior is not desired, you may use the `forkDaemon` or `forkIn` methods.
fork31 )32
33 // Join the monitor and Fibonacci fibers to ensure they complete34 yield* import Fiber
Fiber.const join: <number, never>(self: Fiber.Fiber<number, never>) => Effect.Effect<number, never, never>
Joins the fiber, which suspends the joining fiber until the result of the
fiber has been determined. Attempting to join a fiber that has erred will
result in a catchable error. Joining an interrupted fiber will result in an
"inner interruption" of this fiber, unlike interruption triggered by
another fiber, "inner interruption" can be caught and recovered.
join(const monitorFiber: Fiber.RuntimeFiber<number, never>
monitorFiber)35 const const result: number
result = yield* import Fiber
Fiber.const join: <number, never>(self: Fiber.Fiber<number, never>) => Effect.Effect<number, never, never>
Joins the fiber, which suspends the joining fiber until the result of the
fiber has been determined. Attempting to join a fiber that has erred will
result in a catchable error. Joining an interrupted fiber will result in an
"inner interruption" of this fiber, unlike interruption triggered by
another fiber, "inner interruption" can be caught and recovered.
join(const fibFiber: Fiber.RuntimeFiber<number, never>
fibFiber)36
37 namespace console
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`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
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:
```js
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
```
console.(method) 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)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
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()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log(`fibonacci result: ${const result: number
result}`)38})39
40// Function to monitor and log the number of active fibers41const const monitorFibers: (supervisor: Supervisor.Supervisor<Array<Fiber.RuntimeFiber<any, any>>>) => Effect.Effect<void>
monitorFibers = (42 (parameter) supervisor: Supervisor.Supervisor<Fiber.RuntimeFiber<any, any>[]>
supervisor: import Supervisor
Supervisor.interface Supervisor<out T>
namespace Supervisor
Supervisor<interface Array<T>
Array<import Fiber
Fiber.interface RuntimeFiber<out A, out E = never>
A runtime fiber that is executing an effect. Runtime fibers have an
identity and a trace.
RuntimeFiber<any, any>>>43): import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<void> =>44 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<Fiber.RuntimeFiber<any, any>[], never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<Fiber.RuntimeFiber<any, any>[], never, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {45 const const fibers: Fiber.RuntimeFiber<any, any>[]
fibers = yield* (parameter) supervisor: Supervisor.Supervisor<Fiber.RuntimeFiber<any, any>[]>
supervisor.(property) Supervisor<RuntimeFiber<any, any>[]>.value: Effect.Effect<Fiber.RuntimeFiber<any, any>[], never, never>
Returns an `Effect` that succeeds with the value produced by this
supervisor. This value may change over time, reflecting what the supervisor
produces as it supervises fibers.
value // Get the current set of fibers46 namespace console
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`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and
[`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for
more information.
Example using the global `console`:
```js
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:
```js
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
```
console.(method) 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)`](http://man7.org/linux/man-pages/man3/printf.3.html)
(the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)).
```js
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()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
log(`number of fibers: ${const fibers: Fiber.RuntimeFiber<any, any>[]
fibers.(property) Array<RuntimeFiber<any, any>>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length}`)47 })48
49// Recursive Fibonacci calculation, spawning fibers for each recursive step50const const fib: (n: number) => Effect.Effect<number>
fib = ((parameter) n: number
n: number): import Effect
Effect.interface Effect<out A, out E = never, out R = never>
namespace Effect
The `Effect` interface defines a value that lazily describes a workflow or job.
The workflow requires some context `R`, and may fail with an error of type `E`,
or succeed with a value of type `A`.
`Effect` values model resourceful interaction with the outside world, including
synchronous, asynchronous, concurrent, and parallel interaction. They use a
fiber-based concurrency model, with built-in support for scheduling, fine-grained
interruption, structured concurrency, and high scalability.
To run an `Effect` value, you need a `Runtime`, which is a type that is capable
of executing `Effect` values.
Effect<number> =>51 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<void, never, never>>, number>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, number, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {52 if ((parameter) n: number
n <= 1) {53 return 154 }55 yield* import Effect
Effect.const sleep: (duration: DurationInput) => Effect.Effect<void>
Returns an effect that suspends for the specified duration. This method is
asynchronous, and does not actually block the fiber executing the effect.
sleep("500 millis") // Simulate work by delaying56
57 // Fork two fibers for the recursive Fibonacci calls58 const const fiber1: Fiber.RuntimeFiber<number, never>
fiber1 = yield* import Effect
Effect.const fork: <number, never, never>(self: Effect.Effect<number, never, never>) => Effect.Effect<Fiber.RuntimeFiber<number, never>, never, never>
Returns an effect that forks this effect into its own separate fiber,
returning the fiber immediately, without waiting for it to begin executing
the effect.
You can use the `fork` method whenever you want to execute an effect in a
new fiber, concurrently and without "blocking" the fiber executing other
effects. Using fibers can be tricky, so instead of using this method
directly, consider other higher-level methods, such as `raceWith`,
`zipPar`, and so forth.
The fiber returned by this method has methods to interrupt the fiber and to
wait for it to finish executing the effect. See `Fiber` for more
information.
Whenever you use this method to launch a new fiber, the new fiber is
attached to the parent fiber's scope. This means when the parent fiber
terminates, the child fiber will be terminated as well, ensuring that no
fibers leak. This behavior is called "auto supervision", and if this
behavior is not desired, you may use the `forkDaemon` or `forkIn` methods.
fork(const fib: (n: number) => Effect.Effect<number>
fib((parameter) n: number
n - 2))59 const const fiber2: Fiber.RuntimeFiber<number, never>
fiber2 = yield* import Effect
Effect.const fork: <number, never, never>(self: Effect.Effect<number, never, never>) => Effect.Effect<Fiber.RuntimeFiber<number, never>, never, never>
Returns an effect that forks this effect into its own separate fiber,
returning the fiber immediately, without waiting for it to begin executing
the effect.
You can use the `fork` method whenever you want to execute an effect in a
new fiber, concurrently and without "blocking" the fiber executing other
effects. Using fibers can be tricky, so instead of using this method
directly, consider other higher-level methods, such as `raceWith`,
`zipPar`, and so forth.
The fiber returned by this method has methods to interrupt the fiber and to
wait for it to finish executing the effect. See `Fiber` for more
information.
Whenever you use this method to launch a new fiber, the new fiber is
attached to the parent fiber's scope. This means when the parent fiber
terminates, the child fiber will be terminated as well, ensuring that no
fibers leak. This behavior is called "auto supervision", and if this
behavior is not desired, you may use the `forkDaemon` or `forkIn` methods.
fork(const fib: (n: number) => Effect.Effect<number>
fib((parameter) n: number
n - 1))60
61 // Join the fibers to retrieve their results62 const const v1: number
v1 = yield* import Fiber
Fiber.const join: <number, never>(self: Fiber.Fiber<number, never>) => Effect.Effect<number, never, never>
Joins the fiber, which suspends the joining fiber until the result of the
fiber has been determined. Attempting to join a fiber that has erred will
result in a catchable error. Joining an interrupted fiber will result in an
"inner interruption" of this fiber, unlike interruption triggered by
another fiber, "inner interruption" can be caught and recovered.
join(const fiber1: Fiber.RuntimeFiber<number, never>
fiber1)63 const const v2: number
v2 = yield* import Fiber
Fiber.const join: <number, never>(self: Fiber.Fiber<number, never>) => Effect.Effect<number, never, never>
Joins the fiber, which suspends the joining fiber until the result of the
fiber has been determined. Attempting to join a fiber that has erred will
result in a catchable error. Joining an interrupted fiber will result in an
"inner interruption" of this fiber, unlike interruption triggered by
another fiber, "inner interruption" can be caught and recovered.
join(const fiber2: Fiber.RuntimeFiber<number, never>
fiber2)64
65 return const v1: number
v1 + const v2: number
v2 // Combine the results66 })67
68import Effect
Effect.const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<void>
Executes an effect and returns a `Promise` that resolves with the result.
Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises.
If the effect fails, the returned Promise will be rejected with the error.
runPromise(const program: Effect.Effect<void, never, never>
program)69/*70Output:71number of fibers: 072number of fibers: 273number of fibers: 674number of fibers: 1475number of fibers: 3076number of fibers: 6277number of fibers: 12678number of fibers: 25479number of fibers: 51080number of fibers: 102281number of fibers: 203482number of fibers: 379583number of fibers: 581084number of fibers: 647485number of fibers: 494286number of fibers: 251587number of fibers: 83288number of fibers: 17089number of fibers: 1890number of fibers: 091fibonacci result: 1094692*/