Fallback
On this page
orElse
We can attempt one effect, and if it fails, we can try another effect using the Effect.orElse
combinator:
ts
import {Effect } from "effect"constsuccess =Effect .succeed ("success")constfailure =Effect .fail ("failure")constfallback =Effect .succeed ("fallback")constprogram1 =Effect .orElse (success , () =>fallback )console .log (Effect .runSync (program1 )) // Output: "success"constprogram2 =Effect .orElse (failure , () =>fallback )console .log (Effect .runSync (program2 )) // Output: "fallback"
ts
import {Effect } from "effect"constsuccess =Effect .succeed ("success")constfailure =Effect .fail ("failure")constfallback =Effect .succeed ("fallback")constprogram1 =Effect .orElse (success , () =>fallback )console .log (Effect .runSync (program1 )) // Output: "success"constprogram2 =Effect .orElse (failure , () =>fallback )console .log (Effect .runSync (program2 )) // Output: "fallback"
orElseFail / orElseSucceed
These two operators modify the original failure by replacing it with constant succeed or failure values.
The Effect.orElseFail
will always replace the original failure with the new one:
ts
import {Effect } from "effect"classNegativeAgeError {readonly_tag = "NegativeAgeError"constructor(readonlyage : number) {}}classIllegalAgeError {readonly_tag = "IllegalAgeError"constructor(readonlyage : number) {}}constvalidate = (age : number):Effect .Effect <number,NegativeAgeError |IllegalAgeError > => {if (age < 0) {returnEffect .fail (newNegativeAgeError (age ))} else if (age < 18) {returnEffect .fail (newIllegalAgeError (age ))} else {returnEffect .succeed (age )}}constprogram1 =Effect .orElseFail (validate (3), () => "invalid age")
ts
import {Effect } from "effect"classNegativeAgeError {readonly_tag = "NegativeAgeError"constructor(readonlyage : number) {}}classIllegalAgeError {readonly_tag = "IllegalAgeError"constructor(readonlyage : number) {}}constvalidate = (age : number):Effect .Effect <number,NegativeAgeError |IllegalAgeError > => {if (age < 0) {returnEffect .fail (newNegativeAgeError (age ))} else if (age < 18) {returnEffect .fail (newIllegalAgeError (age ))} else {returnEffect .succeed (age )}}constprogram1 =Effect .orElseFail (validate (3), () => "invalid age")
The Effect.orElseSucceed
will always replace the original failure with a success value, so the resulting effect cannot fail:
ts
constprogram2 =Effect .orElseSucceed (validate (3), () => 0)
ts
constprogram2 =Effect .orElseSucceed (validate (3), () => 0)
firstSuccessOf
The firstSuccessOf
operator simplifies running a series of effects and returns the result of the first one that succeeds. If none of the effects succeed, the resulting effect will fail with the error of the last effect in the series.
This operator utilizes Effect.orElse
to combine multiple effects into a single effect.
In the following example, we attempt to retrieve a configuration from different nodes. If retrieving from the primary node fails, we successively try retrieving from the next available nodes until we find a successful result:
ts
import {Effect ,Console } from "effect"interfaceConfig {// ...}constmakeConfig = (/* ... */):Config => ({})constremoteConfig = (name : string):Effect .Effect <Config ,Error > =>Effect .gen (function* (_ ) {if (name === "node3") {yield*_ (Console .log (`Config for ${name } found`))returnmakeConfig ()} else {yield*_ (Console .log (`Unavailable config for ${name }`))return yield*_ (Effect .fail (newError ()))}})constmasterConfig =remoteConfig ("master")constnodeConfigs = ["node1", "node2", "node3", "node4"].map (remoteConfig )constconfig =Effect .firstSuccessOf ([masterConfig , ...nodeConfigs ])console .log (Effect .runSync (config ))/*Output:Unavailable config for masterUnavailable config for node1Unavailable config for node2Config for node3 found{}*/
ts
import {Effect ,Console } from "effect"interfaceConfig {// ...}constmakeConfig = (/* ... */):Config => ({})constremoteConfig = (name : string):Effect .Effect <Config ,Error > =>Effect .gen (function* (_ ) {if (name === "node3") {yield*_ (Console .log (`Config for ${name } found`))returnmakeConfig ()} else {yield*_ (Console .log (`Unavailable config for ${name }`))return yield*_ (Effect .fail (newError ()))}})constmasterConfig =remoteConfig ("master")constnodeConfigs = ["node1", "node2", "node3", "node4"].map (remoteConfig )constconfig =Effect .firstSuccessOf ([masterConfig , ...nodeConfigs ])console .log (Effect .runSync (config ))/*Output:Unavailable config for masterUnavailable config for node1Unavailable config for node2Config for node3 found{}*/
If the collection provided to the Effect.firstSuccessOf
function is empty,
it will throw an IllegalArgumentException
error.