t3code 基于 Effect 的 Alchemy 2.0.0-beta.61 解读:Workers Cache、Zone Routes 与状态同步
2026/9/13 3:53:35 网站建设 项目流程

t3code 基于 Effect 的 Alchemy 2.0.0-beta.61 解读:Workers Cache、Zone Routes 与状态同步

【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code

本指南以开源仓库 alchemy-effect 的 v2.0.0-beta.61 版本说明为骨架,逐项剖析该版本引入的 Workers Cache 与 Effect 原生ExecutionContext、Wrangler 风格 Zone Routes、alchemy sync状态收敛、完整 Workflows API、资源类型别名等能力,并结合 alchemy-effect 源码 印证其底层实现与调用链,帮助你掌握这套 Effect 原生基础设施即代码框架的版本演进与迁移要点。

版本概览与破坏性变更

beta.61 是一个以可靠性修复为主、能力扩充为辅的版本:Workers Cache 以绑定和 prop 双重形态落地、WorkerExecutionContext升级为 Effect 包装、Zone Routes 支持 Wrangler 风格配置、alchemy sync可修复云端漂移、Workflows API 补全重试/回滚/事件、资源类型别名修复 beta.59 重命名遗留问题。升级前需注意以下三处破坏性变更:

  • workflow.create改用原生 options 对象create(input)变为create({ params: input }),同时解锁idretention配置(对应 PR #611)。
  • WorkerExecutionContext变为 Effect 包装:不再直接暴露原始cf.ExecutionContextwaitUntil接收Effect并需yield*使用(对应 PR #752)。
  • 最低要求 effect>=4.0.0-beta.93:effect 将UrlParams.makeUrl迁移至Url.make,peer 依赖下限随之抬高(对应 PR #748)。

Workers Cache:绑定与 prop 双形态落地

Workers Cache 是 Cloudflare 置于 Worker 入口前的区域性分层缓存。本版本中它同时以绑定(binding)prop两种形态出现(对应 PR #752)。

Effect 原生 Worker 的Cloudflare.cache()

Effect 原生的 Worker 通过Cloudflare.cache()启用 Workers Cache,该调用同时返回带类型的 purge 客户端:

Effect.gen(function* () { // init: enables Workers Cache on this Worker at deploy time const { purge } = yield* Cloudflare.cache({ crossVersionCache: true }); return { fetch: Effect.gen(function* () { const request = yield* HttpServerRequest; if (request.url.startsWith("/invalidate")) { yield* purge({ tags: ["products"] }); // typed CachePurgeError return HttpServerResponse.text("purged"); } return HttpServerResponse.text("hello", { headers: { "Cache-Control": "public, max-age=300, stale-while-revalidate=3600", "Cache-Tag": "products", }, }); }), }; })

从源码看,Cache.ts 中cache()的实现逻辑是:在 init 阶段通过Worker宿主向 Namespace 推送一个cache: { enabled, crossVersionCache }绑定,从而在部署时开启缓存;返回的CacheClient.purge则委托给 init 阶段延迟解析的exec.cache.purge,在请求处理器中解析为真实逐事件上下文。CacheOptions支持两个选项:

  • enabled:是否在调用 Worker 前检查缓存,默认true
  • crossVersionCache:是否跨 Worker 版本共享缓存响应,默认false(缓存默认按单版本隔离,每次部署都会冷启动)。

Async Worker 的 prop 形态

非 Effect 的 Async Worker 使用 prop 形态,配置项一致:

const worker = yield* Cloudflare.Worker("Api", { main: "./src/api.ts", cache: { enabled: true, crossVersionCache: true }, });

缓存命中与否由标准响应头控制:Cache-Control(含stale-while-revalidate)控制有效期、Cache-Tag支持按标签 purge、Vary用于内容协商——这与 Cache.ts 中的注释描述完全一致。

Effect 原生ExecutionContext

旧版WorkerExecutionContext直接把原始cf.ExecutionContext交给你;现在它是 Effect 包装——与DurableObjectState类似,可以从 Worker 的init 闭包(或任意 Layer)中yield*,其方法会解析到真实的逐事件上下文:

Effect.gen(function* () { const exec = yield* Cloudflare.WorkerExecutionContext; // init return { fetch: Effect.gen(function* () { // respond now, finish work in the background yield* exec.waitUntil(journal.record(entry).pipe(Effect.delay("5 seconds"))); return HttpServerResponse.text("ok"); }), }; })

迁移是机械性的:ctx.waitUntil(promise)变为yield* exec.waitUntil(effect)。对应实现位于 Worker.ts:WorkerExecutionContext是基于 EffectContext.Service的服务,提供deferredExecutionContext(延迟解析)与liveExecutionContext(实时解析)两种形态,init 阶段可访问,而raw仅在请求处理器内可用。

Workers 上的 Zone Routes

Cloudflare.Worker通过新增的routesprop 支持 Wrangler 风格的 zone 路由(对应 PR #438,由社区贡献者 utopy 提供):

yield* Cloudflare.Worker("Api", { main: import.meta.filename, routes: [ { pattern: "api.example.com/*", zoneName: "example.com" }, { pattern: "example.com/api/*", zoneId: "<YOUR_ZONE_ID>" }, ], });

每条路由项接受zoneName/zoneId(对应 Wrangler 的等价物)或zone引用;省略 zone 时,从 pattern 的 hostname 自动推断。路由在部署时进行 reconcile、销毁时清理。

alchemy sync:修复云端状态漂移

云状态会漂移:有人在 dashboard 里改了一个资源、某个 bucket 被删除、标签被改乱。alchemy sync在不重新运行 stack 程序的前提下,将云端收敛回最后一次部署的状态(对应 PR #766):

alchemy sync ./alchemy.run.ts --stage prod # detect + repair alchemy sync ./alchemy.run.ts --stage prod --dry-run # detect only

对每个资源,它执行 observe → compare → converge 三步:read观察真实云状态,与持久化属性做深度比较判定unchanged或 drifted,漂移则用持久化 props 作为期望状态交由reconcile修复。从 CLI 注册逻辑看,syncCommanddeploy共享边界处的新鲜状态存储(见 Cli/main.ts),确保收敛基于最近部署的期望状态。关键行为:

  • 被外部删除的资源按同一 instance id 重建,因此确定性物理名会以完全相同的方式重新生成;
  • 资源并发同步,全部尝试完成后才聚合失败结果。

Workflows:重试、回滚与事件

Effect 原生 Workflow 包装现在完整覆盖 Workers API 面,与原生 binding 1:1 对应(对应 PR #611,由 Gerben Mulder 贡献)。

create的原生 options 对象

create接收原生 options 对象——即上文提到的破坏性变更——同时解锁idretention

- const instance = yield* workflow.create({ orderId: "abc" }); + const instance = yield* workflow.create({ + id: "order-abc", + params: { orderId: "abc" }, + retention: { successRetention: "1 day", errorRetention: "7 days" }, + });

task的重试与回滚

task新增 retries、timeout 和 rollback,WorkflowStepContext暴露当前尝试次数:

const result = yield* Cloudflare.Workflows.task( "call-api", Effect.gen(function* () { const context = yield* Cloudflare.Workflows.WorkflowStepContext; return { attempt: context.attempt }; }), { retries: { limit: 3, delay: "5 seconds", backoff: "linear" }, rollback: ({ output }) => (output ? cleanup(output.id) : Effect.void), }, );

waitForEvent事件等待

waitForEvent将实例挂起,直到匹配的sendEvent到达:

// inside the workflow const approval = yield* Cloudflare.Workflows.waitForEvent<{ approved: boolean }>( "approval", { type: "approval", timeout: "1 day" }, ); // from outside yield* instance.sendEvent({ type: "approval", payload: { approved: true } });

这些 API 与原生step.waitForEvent一一对应(见 Workflow.ts)。createBatchrestart、rollback 状态与扩展的事件元数据补齐了整个 API 面,详见 Workflows 文档。

资源类型别名:修复 beta.59 重命名

重命名资源的类型字符串曾会让旧名下持久化的状态孤立——provider 查找在旧类型上失败。现在资源可以声明旧名称(对应 PR #765):

export const Queue = Resource<Queue>("Cloudflare.Queues.Queue", { aliases: ["Cloudflare.Queue"], });

从 Resource.ts 看,ResourceOptions.aliases作为字符串数组保存旧类型名,并复制到资源的Aliases元数据中。planapplydestroylogstail全部通过别名解析 provider;一次 noop deploy 会将状态行迁移到规范名称。beta.59 命名空间对齐中改名的全部74 个资源都标注了改名前的别名——因此 beta.58 及更早版本写入的状态现在可以干净地 deploy、destroy、replace,而不再在旧类型上报错。

AI Gateway BYOK:AI.ProviderKey

AI Gateway 上的自带密钥(BYOK)provider 需要两个协调资源——Secrets Store 中名称严格为{gatewayId}_{providerSlug}_{alias}Secret,以及引用它的GatewayProviderCloudflare.AI.ProviderKey将这一契约封装为单个资源(对应 PR #586,由 Alex 贡献):

const { secret, gatewayProvider } = yield* Cloudflare.AI.ProviderKey("OpenAiKey", { store, gatewayId: gateway.gatewayId, providerSlug: "openai", value: yield* Config.redacted("OPENAI_API_KEY"), });

value通过Config.redacted从环境读取敏感密钥,避免明文写入 stack 程序。详见 AI Gateway 文档。

Lambda 异步调用配置

Lambda 的异步调用设置——重试、事件年龄、成功/失败目标——以eventInvokeConfigprop 落在FunctionAlias上(对应 PR #627,由 José Netto 贡献):

const fn = yield* AWS.Lambda.Function("AsyncFn", { main: "./src/handler.ts", eventInvokeConfig: { maximumRetryAttempts: 0, maximumEventAgeInSeconds: 60, destinationConfig: { OnFailure: { Destination: queue.queueArn }, }, }, });

源码中eventInvokeConfig在 Function.ts 与 Alias.ts 均有声明,且支持通过AliasProps.eventInvokeConfig将配置限定到特定 alias,配置详情见 EventInvokeConfig.ts。

R2 Bucket 的cors恢复

v1 中Cloudflare.R2.Bucket就有的corsprop 在本版本恢复(对应 PR #771)——面向浏览器 range-read(如 PMTiles)的公开 bucket 可以在 stack 中声明 CORS,而不再需要带外配置:

const bucket = yield* Cloudflare.R2.Bucket("Tiles", { domains: [{ name: "tiles.example.com" }], cors: [ { allowedMethods: ["GET", "HEAD"], allowedOrigins: ["https://map.example.com"], allowedHeaders: ["range"], exposeHeaders: ["etag", "content-range"], maxAgeSeconds: 3600, }, ], });

规则使用扁平的 S3 风格 shape,并像lifecycleRules一样做 observed vs desired 的 reconcile——带外漂移与既有资源采纳都能正确收敛。

可靠性修复清单

本版本还包含一批面向可靠性的修复("Also in this release"):

  • Worker 元数据变更现在真正部署(#747):compatibility flags/date、observability、placement、limits、binding 变更通过元数据哈希并入更新 diff;此前它们会被计划为 noop 而静默不发布。升级后首次部署会对每个 Worker 做一次性更新以回填哈希。由 Alex 贡献。
  • Wedged stacks 可恢复(#767、#770):部署在 create 中途被打断曾导致持久化一行 Output 值属性无法往返的状态,使后续每次plan/deploy/destroy崩溃。现在审计了每个 provider 的read/diff,引擎会重新驱动 create,reconcile 收敛到半创建的资源上。
  • 脚本上传对每个 binding-target-not-found 错误重试(#753):覆盖 KV、R2、D1、Queues、DO classes、Hyperdrive、Vectorize 等,应对 Cloudflare 部署期的传播延迟。
  • Resource.ref值在 Workerenv中原生绑定(#756):作为 env 绑定传入的 ref 此前会退化为纯 JSON 环境变量并在运行时出错;现在 ref 与本地声明的资源精确同等地分类。
  • 单个 Worker 支持多个队列消费者(#466):事件分发对每个事件类型运行全部 listener,不再让第一个队列订阅吞掉其余。由 Leonardo E. Dominguez 贡献。
  • 状态存储错误信息可操作(#737):梳理了 30 天的生产 traces,空StateStoreError:消息、不透明的 decode 错误、JSON 解析崩溃现在会暴露真实消息(未授权 store 会提示运行alchemy login)。
  • 测试套件通过 Windows(#735):包含两个真实产品修复——Drizzle.Schema曾把 OS 原生路径传给 drizzle-kit(反斜杠是 glob 转义符),Bundle.PurePlugin可能被node_modules之上的散落package.json劫持。
  • Drizzle 查询链是真正的 Effect(#750):db.select()...链现在暴露完整 Effect 协议,可与Effect.all等组合,而不再自旋 run loop。
  • PlanetScale 继承角色按成员资格比较(#761):API 返回顺序不再强制PostgresRole替换。由 Gerben Mulder 贡献。
  • globalOutbound: nullWorkerLoader中被保留(#746):文档化的"阻止所有出站网络访问"信号不再被静默强制转为默认访问。由 Alex 贡献。
  • Binding 托管的 DO classes 加入 precreate stub(#764):修复 worker↔container 循环的首次部署上Worker did not expose Durable Object namespace。由 Daniel Gangl 贡献。
  • alchemy dev不再打印 bun 的良性 tsconfig fd 警告(#768)。

后续阅读

  • Workflows
  • Workers
  • Custom Domains & Routes
  • AI Gateway
  • 完整变更记录见仓库 CHANGELOG.md(v2.0.0-beta.61条目)

【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询