Skip to content

Examples

For our API calls to third-party services, we have a few requirements. We want to ensure that if the entire function takes more than 4 seconds to execute, it’s interrupted. Additionally, we’ll set up the system to retry the API call a maximum of 2 times.

Solution

1
import {
import NodeRuntime
NodeRuntime
} from "@effect/platform-node"
2
import {
import Console
Console
,
import Effect
Effect
} from "effect"
3
4
const
const getJson: (url: string) => Effect.Effect<unknown, UnknownException, never>
getJson
= (
(parameter) url: string
url
: string) =>
5
import Effect
Effect
.
const tryPromise: <unknown>(try_: (signal: AbortSignal) => PromiseLike<unknown>) => Effect.Effect<unknown, UnknownException, never> (+1 overload)

Create an `Effect` that when executed will construct `promise` and wait for its result, errors will produce failure as `unknown`. An optional `AbortSignal` can be provided to allow for interruption of the wrapped Promise api.

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

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

then
((
(parameter) res: Response
res
) => {
7
if (!
(parameter) res: Response
res
.
(property) Response.ok: boolean
ok
) {
8
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) globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](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
("error")
9
throw new
var Error: ErrorConstructor new (message?: string) => Error
Error
(
(parameter) res: Response
res
.
(property) Response.statusText: string
statusText
)
10
}
11
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) globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](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
("ok")
12
return
(parameter) res: Response
res
.
(property) BodyMixin.json: () => Promise<unknown>
json
() as unknown
13
})
14
)
15
16
const
const program: (url: string) => Effect.Effect<unknown, never, never>
program
= (
(parameter) url: string
url
: string) =>
17
const getJson: (url: string) => Effect.Effect<unknown, UnknownException, never>
getJson
(
(parameter) url: string
url
).
(method) Pipeable.pipe<Effect.Effect<unknown, UnknownException, never>, Effect.Effect<unknown, UnknownException, never>, Effect.Effect<unknown, UnknownException | TimeoutException, never>, Effect.Effect<...>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>, cd: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
18
import Effect
Effect
.
const retry: <UnknownException, { times: number; }>(options: { times: number; }) => <A, R>(self: Effect.Effect<A, UnknownException, R>) => Effect.Effect<...> (+3 overloads)

Retries according to the options provided

retry
({
(property) times: number
times
: 2 }),
19
import Effect
Effect
.
const timeout: (duration: DurationInput) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | TimeoutException, R> (+1 overload)

Returns an effect that will timeout this effect, failing with a `Cause.TimeoutException` if the timeout elapses before the effect has produced a value. If the timeout elapses without producing a value, the running effect will be safely interrupted. WARNING: The effect returned by this method will not itself return until the underlying effect is actually interrupted. This leads to more predictable resource utilization. If early return is desired, then instead of using `effect.timeout(d)`, use `effect.disconnect.timeout(d)`, which first disconnects the effect's interruption signal before performing the timeout, resulting in earliest possible return, before an underlying effect has been successfully interrupted.

timeout
("4 seconds"),
20
import Effect
Effect
.
const catchAll: <any, void, never, never>(f: (e: any) => Effect.Effect<void, never, never>) => <A, R>(self: Effect.Effect<A, any, R>) => Effect.Effect<void | A, never, R> (+1 overload)

Recovers from all recoverable errors. **Note**: that `Effect.catchAll` will not recover from unrecoverable defects. To recover from both recoverable and unrecoverable errors use `Effect.catchAllCause`.

catchAll
(
import Console
Console
.
const error: (...args: ReadonlyArray<any>) => Effect.Effect<void>
error
)
21
)
22
23
// testing the happy path
24
import NodeRuntime
NodeRuntime
.
const runMain: RunMain <never, unknown>(effect: Effect.Effect<unknown, never, never>, options?: { readonly disableErrorReporting?: boolean | undefined; readonly disablePrettyLogger?: boolean | undefined; readonly teardown?: Teardown | undefined; }) => void (+1 overload)
runMain
(
25
const program: (url: string) => Effect.Effect<unknown, never, never>
program
("https://dummyjson.com/products/1?delay=1000")
26
)
27
/*
28
Output:
29
ok
30
*/
31
32
// testing the timeout
33
// NodeRuntime.runMain(
34
// program("https://dummyjson.com/products/1?delay=5000")
35
// )
36
/*
37
Output:
38
TimeoutException
39
*/
40
41
// testing API errors
42
// NodeRuntime.runMain(
43
// program("https://dummyjson.com/auth/products/1?delay=500")
44
// )
45
/*
46
Output:
47
error
48
error
49
error
50
UnknownException: Forbidden
51
*/

We want to implement a mechanism to retry an API call only if it encounters certain types of errors.

Solution

1
import {
import NodeRuntime
NodeRuntime
} from "@effect/platform-node"
2
import {
import Console
Console
,
import Effect
Effect
} from "effect"
3
4
class
class Err
Err
extends
var Error: ErrorConstructor
Error
{
5
constructor(
6
(parameter) message: string
message
: string,
7
readonly
(property) Err.status: number
status
: number
8
) {
9
super(
(parameter) message: string
message
)
10
}
11
}
12
13
const
const getJson: (url: string) => Effect.Effect<unknown, Err, never>
getJson
= (
(parameter) url: string
url
: string) =>
14
import Effect
Effect
.
const tryPromise: <unknown, Err>(options: { readonly try: (signal: AbortSignal) => PromiseLike<unknown>; readonly catch: (error: unknown) => Err; }) => Effect.Effect<unknown, Err, never> (+1 overload)

Create an `Effect` that when executed will construct `promise` and wait for its result, errors will produce failure as `unknown`. An optional `AbortSignal` can be provided to allow for interruption of the wrapped Promise api.

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

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

then
((
(parameter) res: Response
res
) => {
17
if (!
(parameter) res: Response
res
.
(property) Response.ok: boolean
ok
) {
18
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) globalThis.Console.log(message?: any, ...optionalParams: any[]): void

Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](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
(
(parameter) res: Response
res
.
(property) Response.status: number
status
)
19
throw new
constructor Err(message: string, status: number): Err
Err
(
(parameter) res: Response
res
.
(property) Response.statusText: string
statusText
,
(parameter) res: Response
res
.
(property) Response.status: number
status
)
20
}
21
return
(parameter) res: Response
res
.
(property) BodyMixin.json: () => Promise<unknown>
json
() as unknown
22
}),
23
(property) catch: (error: unknown) => Err
catch
: (
(parameter) e: unknown
e
) =>
(parameter) e: unknown
e
as
class Err
Err
24
})
25
26
const
const program: (url: string) => Effect.Effect<unknown, never, never>
program
= (
(parameter) url: string
url
: string) =>
27
const getJson: (url: string) => Effect.Effect<unknown, Err, never>
getJson
(
(parameter) url: string
url
).
(method) Pipeable.pipe<Effect.Effect<unknown, Err, never>, Effect.Effect<unknown, Err, never>, Effect.Effect<unknown, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<unknown, Err, never>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
28
// Retry if the error is a 403
29
import Effect
Effect
.
const retry: <Err, { while: (err: Err) => boolean; }>(options: { while: (err: Err) => boolean; }) => <A, R>(self: Effect.Effect<A, Err, R>) => Effect.Effect<A, Err, R> (+3 overloads)

Retries according to the options provided

retry
({
(property) while: (err: Err) => boolean
while
: (
(parameter) err: Err
err
) =>
(parameter) err: Err
err
.
(property) Err.status: number
status
=== 403 }),
30
import Effect
Effect
.
const catchAll: <any, void, never, never>(f: (e: any) => Effect.Effect<void, never, never>) => <A, R>(self: Effect.Effect<A, any, R>) => Effect.Effect<void | A, never, R> (+1 overload)

Recovers from all recoverable errors. **Note**: that `Effect.catchAll` will not recover from unrecoverable defects. To recover from both recoverable and unrecoverable errors use `Effect.catchAllCause`.

catchAll
(
import Console
Console
.
const error: (...args: ReadonlyArray<any>) => Effect.Effect<void>
error
)
31
)
32
33
// testing 403
34
import NodeRuntime
NodeRuntime
.
const runMain: RunMain <never, unknown>(effect: Effect.Effect<unknown, never, never>, options?: { readonly disableErrorReporting?: boolean | undefined; readonly disablePrettyLogger?: boolean | undefined; readonly teardown?: Teardown | undefined; }) => void (+1 overload)
runMain
(
35
const program: (url: string) => Effect.Effect<unknown, never, never>
program
("https://dummyjson.com/auth/products/1?delay=1000")
36
)
37
/*
38
Output:
39
403
40
403
41
403
42
403
43
...
44
*/
45
46
// testing 404
47
// NodeRuntime.runMain(program("https://dummyjson.com/-"))
48
/*
49
Output:
50
404
51
Err [Error]: Not Found
52
*/

We can use schedules to run an effect periodically until another long-running effect completes. This can be useful for tasks like polling or periodic logging.

Solution

1
import {
import Effect
Effect
,
import Console
Console
,
import Schedule
Schedule
} from "effect"
2
3
const
const longRunningEffect: Effect.Effect<void, never, never>
longRunningEffect
=
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
("done").
(method) 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
(
4
import Effect
Effect
.
const delay: (duration: DurationInput) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Returns an effect that is delayed from this effect by the specified `Duration`.

delay
("5 seconds")
5
)
6
7
const
const action: Effect.Effect<void, never, never>
action
=
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
("action...")
8
9
const
const schedule: Schedule.Schedule<number, unknown, never>
schedule
=
import Schedule
Schedule
.
const fixed: (interval: DurationInput) => Schedule.Schedule<number>

A schedule that recurs on a fixed interval. Returns the number of repetitions of the schedule so far. If the action run between updates takes longer than the interval, then the action will be run immediately, but re-runs will not "pile up". ``` |-----interval-----|-----interval-----|-----interval-----| |---------action--------||action|-----|action|-----------| ```

fixed
("1.5 seconds")
10
11
const
const program: Effect.Effect<number | void, never, never>
program
=
import Effect
Effect
.
const race: <number, never, never, void, never, never>(self: Effect.Effect<number, never, never>, that: Effect.Effect<void, never, never>) => Effect.Effect<number | void, never, never> (+1 overload)

Returns an effect that races this effect with the specified effect, returning the first successful `A` from the faster side. If one effect succeeds, the other will be interrupted. If neither succeeds, then the effect will fail with some error.

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

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 action: Effect.Effect<void, never, never>
action
,
const schedule: Schedule.Schedule<number, unknown, never>
schedule
),
13
const longRunningEffect: Effect.Effect<void, never, never>
longRunningEffect
14
)
15
16
import Effect
Effect
.
const runPromise: <number | void, never>(effect: Effect.Effect<number | void, never, never>, options?: { readonly signal?: AbortSignal; } | undefined) => Promise<number | void>

Runs an `Effect` workflow, returning a `Promise` which resolves with the result of the workflow or rejects with an error.

runPromise
(
const program: Effect.Effect<number | void, never, never>
program
)
17
/*
18
Output:
19
action...
20
action...
21
action...
22
action...
23
done
24
*/