并行与顺序错误
在 Effect 程序中处理并发与顺序错误,捕获多个失败,并在并发与顺序工作流中实现稳健的错误管理。
在使用 Effect 时,如果发生错误,默认行为是以遇到的第一个错误失败。
示例(在第一个错误上失败)
这里,程序以它遇到的第一个错误 "Oh uh!" 失败。
import { Effect } from "effect"
const fail = Effect.fail("Oh uh!")
const die = Effect.dieMessage("Boom!")
// Run both effects sequentially
const program = Effect.all([fail, die])
Effect.runPromiseExit(program).then(console.log)
/*
Output:
{
_id: 'Exit',
_tag: 'Failure',
cause: { _id: 'Cause', _tag: 'Fail', failure: 'Oh uh!' }
}
*/
并行错误
在某些情况下,你可能会遇到多个错误,尤其是在并发计算期间。当多个任务并发运行时,多个错误可能同时发生。
示例(处理并发计算中的多个错误)
在这个示例中,fail 和 die 这两个 effect 是并发执行的。由于两者都失败,程序会在输出中报告多个错误。
import { Effect } from "effect"
const fail = Effect.fail("Oh uh!")
const die = Effect.dieMessage("Boom!")
// Run both effects concurrently
const program = Effect.all([fail, die], {
concurrency: "unbounded",
}).pipe(Effect.asVoid)
Effect.runPromiseExit(program).then(console.log)
/*
Output:
{
_id: 'Exit',
_tag: 'Failure',
cause: {
_id: 'Cause',
_tag: 'Parallel',
left: { _id: 'Cause', _tag: 'Fail', failure: 'Oh uh!' },
right: { _id: 'Cause', _tag: 'Die', defect: [Object] }
}
}
*/
parallelErrors
Effect 提供了一个名为 Effect.parallelErrors 的函数,它会把并发操作产生的所有失败错误捕获到错误通道中。
示例(捕获多个并发失败)
在这个示例中,Effect.parallelErrors 把 fail1 和 fail2 的错误合并为单个错误。
import { Effect } from "effect"
const fail1 = Effect.fail("Oh uh!")
const fail2 = Effect.fail("Oh no!")
const die = Effect.dieMessage("Boom!")
// Run all effects concurrently and capture all errors
const program = Effect.all([fail1, fail2, die], {
concurrency: "unbounded",
}).pipe(Effect.asVoid, Effect.parallelErrors)
Effect.runPromiseExit(program).then(console.log)
/*
Output:
{
_id: 'Exit',
_tag: 'Failure',
cause: { _id: 'Cause', _tag: 'Fail', failure: [ 'Oh uh!', 'Oh no!' ] }
}
*/
Applicability
注意,Effect.parallelErrors 只适用于失败(failure),不适用于 defect 或中断(interruption)。
顺序错误
在使用 Effect.ensuring 之类的资源安全操作符时,你可能会遇到多个顺序错误。
这是因为无论原始 effect 是否有错误,终结器(finalizer)都是不可中断的,并且总会运行。
示例(处理多个顺序错误)
在这个示例中,fail 和终结器 die 都会导致顺序错误,并且两者都会被捕获。
import { Effect } from "effect"
// Simulate an effect that fails
const fail = Effect.fail("Oh uh!")
// Simulate a finalizer that causes a defect
const die = Effect.dieMessage("Boom!")
// The finalizer 'die' will always run, even if 'fail' fails
const program = fail.pipe(Effect.ensuring(die))
Effect.runPromiseExit(program).then(console.log)
/*
Output:
{
_id: 'Exit',
_tag: 'Failure',
cause: {
_id: 'Cause',
_tag: 'Sequential',
left: { _id: 'Cause', _tag: 'Fail', failure: 'Oh uh!' },
right: { _id: 'Cause', _tag: 'Die', defect: [Object] }
}
}
*/