This page explains various techniques for handling failures and creating fallback mechanisms in the Effect library.
orElse
Effect.orElse allows you to attempt to run an effect, and if it fails, you
can provide a fallback effect to run instead.
This is useful for handling failures gracefully by defining an alternative effect to execute if the first
one encounters an error.
Example (Handling Fallback with Effect.orElse)
orElseFail
Effect.orElseFail allows you to replace the failure from one effect with a
custom failure value. If the effect fails, you can provide a new failure to
be returned instead of the original one.
This function only applies to failed effects. If the effect
succeeds, it will remain unaffected.
Example (Replacing Failure with Effect.orElseFail)
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.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
Replaces the original failure with a new failure value.
orElseFail allows you to replace the failure from one effect with a
custom failure value. If the effect fails, you can provide a new failure to
be returned instead of the original one.
Important: This function only applies to failed effects. If the effect
succeeds, it will remain unaffected.
@see ― mapError if you need to access the error to transform it.
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 and
process.stderr. 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 for
more information.
Example using the global console:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(newError('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
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=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(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
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)
(the arguments are all passed to util.format()).
Runs an effect synchronously and returns the result as an Exit type, which
represents the outcome (success or failure) of the effect.
When to Use
Use runSyncExit to find out whether an effect succeeded or failed,
including any defects, without dealing with asynchronous operations.
Details
The Exit type represents the result of the effect:
If the effect succeeds, the result is wrapped in a Success.
If it fails, the failure information is provided as a Failure containing
a Cause type.
If the effect contains asynchronous operations, runSyncExit will
return an Failure with a Die cause, indicating that the effect cannot be
resolved synchronously.
Effect.orElseSucceed allows you to replace the failure of an effect with a
success value. If the effect fails, it will instead succeed with the provided
value, ensuring the effect always completes successfully.
This is useful when you want to guarantee a successful result regardless of whether the original
effect failed.
The function ensures that any failure is effectively “swallowed” and replaced
by a successful value, which can be helpful for providing default values in
case of failure.
This function only applies to failed effects. If the effect
already succeeds, it will remain unchanged.
Example (Replacing Failure with Success using Effect.orElseSucceed)
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.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
Replaces the original failure with a success value, ensuring the effect
cannot fail.
orElseSucceed allows you to replace the failure of an effect with a
success value. If the effect fails, it will instead succeed with the provided
value, ensuring the effect always completes successfully. This is useful when
you want to guarantee a successful result regardless of whether the original
effect failed.
The function ensures that any failure is effectively "swallowed" and replaced
by a successful value, which can be helpful for providing default values in
case of failure.
Important: This function only applies to failed effects. If the effect
already succeeds, it will remain unchanged.
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 and
process.stderr. 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 for
more information.
Example using the global console:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(newError('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
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=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(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
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)
(the arguments are all passed to util.format()).
Runs an effect synchronously and returns the result as an Exit type, which
represents the outcome (success or failure) of the effect.
When to Use
Use runSyncExit to find out whether an effect succeeded or failed,
including any defects, without dealing with asynchronous operations.
Details
The Exit type represents the result of the effect:
If the effect succeeds, the result is wrapped in a Success.
If it fails, the failure information is provided as a Failure containing
a Cause type.
If the effect contains asynchronous operations, runSyncExit will
return an Failure with a Die cause, indicating that the effect cannot be
resolved synchronously.
// Title: Asynchronous Operation Resulting in Die
import { Effect } from "effect"
console.log(Effect.runSyncExit(Effect.promise(() => Promise.resolve(1))))
// Output:
// {
// _id: 'Exit',
// _tag: 'Failure',
// cause: {
// _id: 'Cause',
// _tag: 'Die',
// defect: [Fiber #0 cannot be resolved synchronously. This is caused by using runSync on an effect that performs async work] {
// fiber: [FiberRuntime],
// _tag: 'AsyncFiberException',
// name: 'AsyncFiberException'
// }
// }
// }
@since ― 2.0.0
runSyncExit(
constprogram:Effect.Effect<number, never, never>
program))
16
/*
17
Output:
18
{ _id: 'Exit', _tag: 'Success', value: 18 }
19
*/
firstSuccessOf
Effect.firstSuccessOf allows you to try multiple effects in sequence, and
as soon as one of them succeeds, it returns that result. If all effects fail,
it returns the error of the last effect in the list.
This is useful when you
have several potential alternatives and want to use the first one that works.
This function is sequential, meaning that the Effect values in the iterable
will be executed in sequence, and the first one that succeeds will determine
the outcome of the resulting Effect value.
Example (Finding Configuration with Fallbacks)
In this example, we try to retrieve a configuration from different nodes. If the primary node fails, we fall back to other nodes until we find a successful configuration.
1
import {
import Effect
@since ― 2.0.0
@since ― 2.0.0
@since ― 2.0.0
Effect,
import Console
Console } from"effect"
2
3
interface
interfaceConfig
Config {
4
Config.host: string
host:string
5
Config.port: number
port:number
6
Config.apiKey: string
apiKey:string
7
}
8
9
// Create a configuration object with sample values
10
const
constmakeConfig: (name:string) =>Config
makeConfig= (
name: string
name:string):
interfaceConfig
Config=> ({
11
Config.host: string
host: `${
name: string
name}.example.com`,
12
Config.port: number
port: 8080,
13
Config.apiKey: string
apiKey: "12345-abcde"
14
})
15
16
// Simulate retrieving configuration from a remote node
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.
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to Use
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.
Creates an Effect that represents a recoverable error.
When to Use
Use this function to explicitly signal an error in an Effect. The error
will keep propagating unless it is handled. You can handle the error with
functions like
catchAll
or
catchTag
.
@see ― succeed to create an effect that represents a successful value.
@example
// Title: Creating a Failed Effect
import { Effect } from"effect"
// ┌─── Effect<never, Error, never>
// ▼
constfailure= Effect.fail(
newError("Operation failed due to network error")
)
@since ― 2.0.0
fail(new
var Error:ErrorConstructor
new (message?:string) => Error
Error(`Config not found for ${
name: string
name}`))
26
}
27
})
28
29
// Define the master configuration and potential fallback nodes
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@param ― callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.
@param ― thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
Runs a series of effects and returns the result of the first successful one.
If none of the effects succeed, it fails with the error from the last effect.
firstSuccessOf allows you to try multiple effects in sequence, and
as soon as one of them succeeds, it returns that result. If all effects fail,
it returns the error of the last effect in the list. This is useful when you
have several potential alternatives and want to use the first one that works.
This function is sequential, meaning that the Effect values in the iterable
will be executed in sequence, and the first one that succeeds will determine
the outcome of the resulting Effect value.
Important: If the collection of effects provided to
firstSuccessOf is empty, it will throw an IllegalArgumentException
error.
@example
import { Effect, Console } from"effect"
interfaceConfig {
host:string
port:number
apiKey:string
}
// Create a configuration object with sample values
constmakeConfig= (name:string):Config=> ({
host: `${name}.example.com`,
port: 8080,
apiKey: "12345-abcde"
})
// Simulate retrieving configuration from a remote node
Executes an effect synchronously, running it immediately and returning the
result.
When to Use
Use runSync to run an effect that does not fail and does not include
any asynchronous operations.
If the effect fails or involves asynchronous work, it will throw an error,
and execution will stop where the failure or async operation occurs.
@see ― runSyncExit for a version that returns an Exit type instead of
throwing an error.
@example
// Title: Synchronous Logging
import { Effect } from"effect"
constprogram= Effect.sync(() => {
console.log("Hello, World!")
return1
})
constresult= Effect.runSync(program)
// Output: Hello, World!
console.log(result)
// Output: 1
@example
// Title: Incorrect Usage with Failing or Async Effects
import { Effect } from "effect"
try {
// Attempt to run an effect that fails
Effect.runSync(Effect.fail("my error"))
} catch (e) {
console.error(e)
}
// Output:
// (FiberFailure) Error: my error
try {
// Attempt to run an effect that involves async work
Effect.runSync(Effect.promise(() => Promise.resolve(1)))
} catch (e) {
console.error(e)
}
// Output:
// (FiberFailure) AsyncFiberException: Fiber #0 cannot be resolved synchronously. This is caused by using runSync on an effect that performs async work
@since ― 2.0.0
runSync(
constconfig:Effect.Effect<Config, Error, never>
config)
39
40
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 and
process.stderr. 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 for
more information.
Example using the global console:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(newError('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
constname='Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
constout=getStreamSomehow();
consterr=getStreamSomehow();
constmyConsole=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(newError('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
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)
(the arguments are all passed to util.format()).