AlchemyCloudflareCluster
Deploys the Cloudflare cluster with Alchemy v2 ("Infrastructure as Effects").
make runs inside an Effect-native Cloudflare.Worker init program. It
registers the four cluster Durable Object classes on the hosting Worker
(bindings, class exports, and SQLite migrations are all owned by Alchemy),
builds the cluster layer together with the user's handler layer into the
isolate-lifetime scope, and returns a handle for wiring the built context
into the Worker's handlers. The user never declares or re-exports Durable
Object classes.
The Wrangler path (CloudflareDurableObjects + CloudflareCluster.layer)
never imports this module; @alchemy.run/cloudflare is an optional peer
dependency needed only here.
Example Declaring a cluster
import * as Cloudflare from "@alchemy.run/cloudflare"import { Effect, Layer } from "effect"import { make } from "@effect/platform-cloudflare/AlchemyCloudflareCluster"import { CloudflareCluster } from "@effect/platform-cloudflare"
export default Cloudflare.Worker("MyApp", { main: import.meta.url}, Effect.gen(function*() { const cluster = yield* make({ entities: [Counter], layer: Layer.mergeAll(CounterLayer, MaintenanceLayer, NightlyReport) })
yield* Cloudflare.Workers.cron("0 * * * *", cluster.wake("hourly-maintenance")) // A ClusterCron fires only after a Cron Trigger wakes its seed singleton yield* Cloudflare.Workers.cron( "30 * * * *", cluster.wake(CloudflareCluster.clusterCronSingletonName("nightly-report")) )
return { fetch: cluster.provide(handler) }}).pipe(Effect.provide(Cloudflare.Workers.CronEventSourceLive)))Constructors
Builds the Cloudflare cluster inside an Effect-native Alchemy Worker.
Details
Always registers all four Durable Object classes (entity, workflow, durable
queue, singleton) on the hosting Worker, so Alchemy owns their bindings and
SQLite migrations across deploys. At runtime it builds
CloudflareCluster.layer merged with the user's handler layer into the
isolate-lifetime Scope โ the Scope is never closed, so do not wrap the
Worker init program in Effect.provide(layer) for cluster services.
The returned handle exposes provide for the Worker's handlers, wake for
user-declared Cron Triggers
(Cloudflare.Workers.cron(expr, cluster.wake("name"))), and the four
native namespace bindings as escape hatches.
A ClusterCron fires only after a Cron Trigger wakes its seed singleton.
Pass CloudflareCluster.clusterCronSingletonName(name) to wake for it.
Signature
declare const make: <ROut, E, RIn>(options: MakeOptions<ROut, E, RIn>) => Effect.Effect<Cluster<ROut | ClusterServices>, E, Cloudflare.Worker | Exclude<RIn, ClusterServices>>Models
The handle returned by AlchemyCloudflareCluster.make.
Gotchas
Namespace bindings and context are available only in the deployed runtime.
Reading them during plan evaluation throws a diagnostic; provide and
wake remain inert during planning.
Signature
interface Cluster<in R = never> { readonly context: Context<R>; readonly entityNamespace: DurableObjectNamespace; readonly provide: <A, E, R2>(effect: Effect<A, E, R2>) => Effect<A, E, Exclude<R2, R>>; readonly queueNamespace: DurableObjectNamespace; readonly singletonNamespace: DurableObjectNamespace; readonly wake: (name: string) => () => Effect<void>; readonly workflowNamespace: DurableObjectNamespace;}ClusterServices
typeThe services make builds on top of the user layer: the cluster Sharding
service, the workflow engine, and the persisted queue factory.
Signature
type ClusterServices = Sharding | WorkflowEngine | PersistedQueueFactoryMakeOptions
interfaceThe entity definitions and handler layer the cluster is built from.
Signature
interface MakeOptions<ROut, E, RIn> { readonly entities: readonly Array<Entity<any, any>>; readonly keepAliveHeartbeat?: Input; readonly layer: Layer<ROut, E, RIn>;}