资讯动态

Effect 事务 API 重构解析:Effect.tx / Effect.txRetry 与原子事务组合(effect-smol)

发布时间:2026/9/15 3:02:45 来源:尧图企业网站定制
Effect 事务 API 重构解析Effect.tx / Effect.txRetry 与原子事务组合effect-smol【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code本指南以 effect-smol 仓库中remove-effect-transactionwith.md变更说明为主线深入解析 Effect 事务TransactionAPI 的重新命名与架构调整Effect.transaction更名为Effect.tx、Effect.retryTransaction更名为Effect.txRetry移除Effect.transactionWith/Effect.withTxState并让嵌套Effect.tx调用自动组合进当前活动事务。读完本文你将掌握新事务 API 的调用方式、嵌套组合与乐观重试的底层机制并理解Tx*系列 API 如何在常见场景中无需显式Transaction依赖即可建立原子事务。变更背景与目标在 effect-smolEffect 库的零依赖、精简实现中事务transaction是协调多个共享可变状态如TxRef的核心机制保证对事务值的修改“要么全部提交、要么全部回滚”all or nothing。本次变更见 changeset 原文是一次面向可用性的 API 重构包含四个核心动作重命名Effect.transaction→Effect.txEffect.retryTransaction→Effect.txRetry移除Effect.transactionWith、Effect.withTxState两个 API 被彻底删除嵌套组合嵌套的Effect.tx调用不再创建新的事务边界而是组合进当前活动事务默认原子性公共的Tx*API如TxRef、TxQueue、TxPubSub等在常见用法中能够自动建立原子事务无需显式提供Transaction服务。该变更被标记为patch级别见 changeset/config.json并已记录在 packages/effect/CHANGELOG.md 中由 mikearnaldi 提交PR #1898。核心 APIEffect.tx 定义事务边界Effect.tx是重构后定义事务边界的主要入口签名如下源码见 packages/effect/src/Effect.tsexport const tx A, E, R( effect: EffectA, E, R ): EffectA, E, ExcludeR, Transaction 它接收一个Effect作为事务体返回的 Effect 在类型层面将Transaction服务需求从环境R中剔除ExcludeR, Transaction即调用方无需再关心事务状态服务是否可用。嵌套组合语义tx在内部通过withFiber检查当前 Fiber 上下文中是否已存在Transaction状态let state Context.getOrUndefined(fiber.context, Transaction) if (state) { return effect as EffectA, E, ExcludeR, Transaction } // 仅在最外层边界创建事务状态 state { journal: new Map(), retry: false }如果已经处于活动事务中直接返回原始 effect复用现有事务的 journal日志与 retry 状态不创建新的嵌套边界如果是最外层创建全新的{ journal: new Map(), retry: false }状态并把整个循环包裹在uninterruptibleMask中确保提交/回滚过程不可中断。这一实现正是 changeset 中所说的“make nestedEffect.txcalls compose into the active transaction”的源码证据嵌套调用是组合compose而非嵌套提交最外层的tx调用负责统一提交或回滚整个组合事务。提交与回滚流程最外层tx通过whileLoop循环执行事务体直到得到确定结果step(exit: Exit.ExitA, E) { if (state.retry || !isTransactionConsistent(state)) { return clearTransaction(state) // 需要重试或冲突清空日志 } if (Exit.isSuccess(exit)) { commitTransaction(fiber, state) // 成功统一提交 } else { clearTransaction(state) // 失败回滚丢弃日志 } result exit }关键辅助函数isTransactionConsistentEffect.ts遍历 journal 中记录的每个TxRef比对ref.version ! version。任一事务值在事务期间被其他事务修改过即判定为冲突commitTransactionEffect.ts对 journal 中值发生变化的TxRef递增version并写回新值随后调度唤醒所有pending等待者clearTransactionEffect.ts重置retry标志并清空 journal相当于回滚。乐观并发与重试Effect.txRetryEffect 的事务采用乐观并发 重试模型。事务在以下两种情况下会重试事务体显式调用Effect.txRetry且任何被访问的事务值发生了变化事务体执行期间某个被访问的事务值因其他事务先提交而发生变化版本不一致。txRetry的实现非常简洁Effect.tsexport const txRetry: Effectnever, never, Transaction flatMap( Transaction, (state) { state.retry true return interrupt } )它读取Transaction服务将state.retry置为true然后通过interrupt中断当前事务体执行。最外层tx的whileLoop检测到state.retry后若当前被访问的事务值已变化则通过awaitPendingTransactionEffect.ts挂起等待——在 journal 中所有被访问的TxRef上注册pending回调任一 ref 被其他事务提交时唤醒重新执行整个事务体若事务值未变化则直接重新执行事务体。典型使用示例从源码 docstring 中可以看到标准用法Effect.ts当读取到旧值时先触发外部更新再请求重试最终返回最新值import { Deferred, Effect, TxRef } from effect const program Effect.gen(function*() { const ref yield* TxRef.make(0) const update yield* Deferred.makevoid() yield* Effect.forkChild( Deferred.await(update).pipe(Effect.andThen(Effect.tx(TxRef.set(ref, 1)))) ) return yield* Effect.tx(Effect.gen(function*() { const value yield* TxRef.get(ref) if (value 0) { yield* Deferred.succeed(update, undefined) return yield* Effect.txRetry } return value })) }) await Effect.runPromise(program) // 1嵌套事务组合的实践源码 docstring 给出了嵌套组合的直接演示Effect.tsimport { Effect, TxRef } from effect const output: Arrayunknown [] const program Effect.gen(function*() { const ref1 yield* TxRef.make(0) const ref2 yield* TxRef.make(0) // 嵌套 tx 调用组合进同一个事务 yield* Effect.tx(Effect.gen(function*() { yield* TxRef.set(ref1, 10) yield* Effect.tx(TxRef.set(ref2, 20)) // 内层复用当前事务不嵌套提交 const sum (yield* TxRef.get(ref1)) (yield* TxRef.get(ref2)) void output.push(Transaction sum: ${sum}) })) void output.push(Final ref1: ${yield* TxRef.get(ref1)}) void output.push(Final ref2: ${yield* TxRef.get(ref2)}) }) Effect.runSync(program) // output [Transaction sum: 30, Final ref1: 10, Final ref2: 20]要点内层Effect.tx(TxRef.set(ref2, 20))并没有创建独立事务而是直接复用外层事务的 journal因此ref1、ref2的修改会在最外层tx结束时一次性原子提交。如果内层嵌套创建独立边界将无法保证这两个修改的原子性。Tx* API 的自动原子事务changeset 的最后一点是“make the publicTx*APIs establish atomic transactions without requiringTransactionin common usage”。以TxRef为例其modify实现packages/effect/src/TxRef.ts充分体现了这一设计export const modify dual(2, A, R( self: TxRefA, f: (current: A) [returnValue: R, newValue: A] ): Effect.EffectR Effect.Transaction.pipe( Effect.flatMap((state) Effect.sync(() { if (!state.journal.has(self)) { state.journal.set(self, { version: self.version, value: self.value }) } const current state.journal.get(self)! const [returnValue, next] f(current.value) current.value next return returnValue }) ), Effect.tx // 自动建立事务边界 ))分析读取Transaction服务状态journal如果该TxRef尚未记录则记录当前的version与value快照在 journal 中执行f实现读-改-写最后通过Effect.tx包裹——当调用方未处于任何事务中时tx自动创建一个原子事务边界并提交当调用方已在事务中时tx复用现有事务。因此在常见用法中直接调用TxRef.get/TxRef.set/TxRef.modify等 API 即可获得原子性而无需像旧 API 那样手动搭建事务状态。TxChunk、TxDeferred、TxPriorityQueue、TxPubSub、TxQueue、TxReentrantLock、TxRef、TxSemaphore等事务集合见 packages/effect/src 目录均遵循这一模式。Transaction 服务模型事务状态的载体是Transaction服务类Effect.ts其结构如下export class Transaction extends Context.Service Transaction, { retry: boolean readonly journal: Map TxRefany, { readonly version: number value: any } } ()(effect/Effect/Transaction) {}journal记录事务访问过的每个TxRef及其进入事务时的version快照和事务内修改的value是冲突检测与提交的根基retry布尔标志由txRetry置位驱动事务体的重试循环。Transaction仍可被显式获取yield* Effect.Transaction用于需要直接操纵事务状态的高级场景例如在测试中手动提供事务服务const runnable Effect.provideService(txEffect, Effect.Transaction, { retry: false, journal: new Map() }) Effect.runSync(runnable) // Transaction complete迁移指南从旧 API 到新 API根据 changeset 与 CHANGELOG 的说明迁移时只需进行机械替换旧 API已移除/重命名新 APIEffect.transaction(effect)Effect.tx(effect)Effect.retryTransactionEffect.txRetryEffect.transactionWith已移除改用Effect.tx嵌套组合自动生效Effect.withTxState已移除改用Transaction服务直接访问注意事项transactionWith/withTxState在源码中已完全不存在直接搜索 packages/effect/src 无任何匹配说明旧 API 已彻底删除而非弃用deprecated嵌套事务语义发生变化旧 API 下嵌套可能产生独立事务新 API 下嵌套tx总是组合进当前活动事务迁移后需确认原代码是否依赖旧的嵌套提交行为如果代码显式传递Transaction服务类型层面tx的返回值已剔除Transaction环境需求ExcludeR, Transaction通常可以简化调用链。小结本次重构把 Effect 事务 API 收敛为三个清晰的概念Effect.tx唯一的事务边界入口最外层创建并提交事务嵌套调用自动组合Effect.txRetry显式请求重试配合乐观并发模型与版本冲突检测实现一致性Tx*API 自动原子性TxRef等事务集合在常见用法下自动建立原子事务降低使用门槛。对于正在使用 effect-smol 或 Effect 生态的开发者本文对应的源码证据Effect.ts、TxRef.ts、CHANGELOG.md可作为深入阅读的起点理解乐观事务、journal 快照与版本冲突检测的完整实现。【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价