已发布 上游基线 bf46254 原文 ↗ 在 GitHub 编辑

并行与顺序错误

在 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!' }
}
*/

并行错误

在某些情况下,你可能会遇到多个错误,尤其是在并发计算期间。当多个任务并发运行时,多个错误可能同时发生。

示例(处理并发计算中的多个错误)

在这个示例中,faildie 这两个 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.parallelErrorsfail1fail2 的错误合并为单个错误。

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] }
  }
}
*/