Skip to content

Add Alchemy deployment for the Cloudflare cluster - #7550

Open
tim-smart wants to merge 3 commits into
eff-698-cloudflare-clusterfrom
eff-988-alchemy-cloudflare-cluster
Open

Add Alchemy deployment for the Cloudflare cluster#7550
tim-smart wants to merge 3 commits into
eff-698-cloudflare-clusterfrom
eff-988-alchemy-cloudflare-cluster

Conversation

@tim-smart

Copy link
Copy Markdown
Contributor

Adds the Alchemy v2 ("Infrastructure as Effects") deployment story for the Cloudflare cluster, stacked on #7322. Closes EFF-988.

AlchemyCloudflareCluster.make runs inside an Effect-native Cloudflare.Worker init program. It registers four library-owned alchemy Durable Object classes (Alchemy owns bindings, class exports, and SQLite migrations), builds CloudflareCluster.layer merged with the user's handler layer into the isolate-lifetime scope, and returns a handle. The user never declares or re-exports DO classes:

export default Cloudflare.Worker("MyApp", {
  main: import.meta.url
}, Effect.gen(function*() {
  const cluster = yield* AlchemyCloudflareCluster.make({
    entities: [Counter],
    layer: Layer.mergeAll(CounterLayer, MaintenanceLayer)
  })

  yield* Cloudflare.Workers.cron("0 * * * *", cluster.wake("hourly-maintenance"))

  return { fetch: cluster.provide(handler) }
}).pipe(Effect.provide(Cloudflare.Workers.CronEventSourceLive)))
  • CloudflareDurableObjectPrograms (revived from Simplify Cloudflare Durable Object framework integration #7385, rebuilt on the current internals) exposes the four Durable Object behaviors as class-independent Effect programs; the alchemy DO classes call them, and the Wrangler classes are untouched.
  • Handle: provide (attaches the built Context), wake(name) (a cron handler for the singleton, no Singleton/ prefix), the four native namespace bindings as escape hatches, and context.
  • alchemy is an optional peer (>=2.0.0-beta <3, dev-pinned to 2.0.0-beta.76); the package index stays alchemy-free, the module is reachable only via @effect/platform-cloudflare/AlchemyCloudflareCluster.
  • Example at packages/platform/cloudflare/examples/alchemy (one entity, one singleton, one Cron Trigger) plus tstyche typetests, both typechecked in normal PR CI. They compile in a dedicated tsconfig.alchemy.json project because the alchemy type graph loads bun globals that clash with the shared tests project's node globals (same reason for the @types/ssh2>@types/node override).
  • Manual workflow_dispatch canary (Alchemy Canary) reinstalls the latest alchemy@beta and reruns the typechecks/typetests.
  • README gains the Alchemy walkthrough, examples pointer, and manual live smoke checklist; the Wrangler section is unchanged.

Two deviations from the handoff snippet, both forced by the actual alchemy@beta.76 surface:

  • Cloudflare.Workers.cron takes a handler function, so cluster.wake(name) returns () => Effect<void> (passed directly to cron) rather than a bare Effect.
  • cron requires CronEventSourceLive provided on the init program (alchemy's documented pattern); the cluster layer itself is still never provided that way.

Runtime unit tests cover the programs and the handle building (internal/alchemyCluster). The alchemy-importing glue is typecheck-only in this repo: alchemy's runtime targets the published effect release, which has diverged from workspace HEAD (e.g. Config.stringConfig.String), so executing alchemy code against the workspace source fails by construction — that skew is exactly what the canary watches. The live alchemy deploy smoke from the README checklist still needs one run by someone with Cloudflare credentials.

Supersedes #7548.

…grams

CloudflareDurableObjectPrograms exposes the entity, workflow, durable queue,
and singleton Durable Object behaviors as Effect programs over a minimal
native state, so frameworks that create their own classes can run them.

AlchemyCloudflareCluster.make runs inside an Effect-native Cloudflare.Worker
init program: it registers four library-owned alchemy Durable Object classes
backed by the programs, builds CloudflareCluster.layer merged with the user
layer into the isolate-lifetime scope, and returns the provide/wake handle
with the native namespace escape hatches. alchemy is an optional peer
dependency and the package index stays free of it.
The minimal example at packages/platform/cloudflare/examples/alchemy (worker
plus alchemy.run.ts, one entity and one singleton) and the tstyche typetests
compile in normal PR CI against the pinned alchemy peer.

They live in their own tsconfig project (tsconfig.alchemy.json, referenced
from the root tsconfig so 'pnpm check' covers it): the alchemy type graph
loads bun globals that clash with the shared tests project's node globals.
An @types/ssh2>@types/node override keeps a second @types/node major out of
the install for the same reason.
The workflow_dispatch-only canary reinstalls the latest alchemy@beta and
reruns the integration typechecks and typetests. The README gains the
Alchemy walkthrough, a pointer to examples/alchemy, and the manual live
smoke checklist; the Wrangler section is unchanged.
@changeset-bot

changeset-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f414380

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 31 packages
Name Type
effect Patch
@effect/ai-anthropic Patch
@effect/ai-openai Patch
@effect/ai-openai-compat Patch
@effect/ai-openrouter Patch
@effect/atom-react Patch
@effect/atom-solid Patch
@effect/atom-vue Patch
@effect/docgen Patch
@effect/doctest Patch
@effect/openapi-generator Patch
@effect/opentelemetry Patch
@effect/platform-browser Patch
@effect/platform-bun Patch
@effect/platform-cloudflare Patch
@effect/platform-deno Patch
@effect/platform-node Patch
@effect/platform-node-shared Patch
@effect/sql-clickhouse Patch
@effect/sql-d1 Patch
@effect/sql-libsql Patch
@effect/sql-mssql Patch
@effect/sql-mysql2 Patch
@effect/sql-pg Patch
@effect/sql-pglite Patch
@effect/sql-sqlite-bun Patch
@effect/sql-sqlite-do Patch
@effect/sql-sqlite-node Patch
@effect/sql-sqlite-react-native Patch
@effect/sql-sqlite-wasm Patch
@effect/vitest Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant