2.0.0-beta.65 - SageMaker HyperPod
beta.65 brings SageMaker HyperPod to the AWS provider:
persistent ML training fleets, Slurm or EKS orchestrated, with
task governance and typed workloads. It also fixes two Worker
bundling bugs that broke deployed apps, and makes destroy and
nuke converge in one pass.
SageMaker HyperPod
Section titled “SageMaker HyperPod”HyperPod is AWS’s persistent fleet for ML training and inference: accelerated instances with automatic health checks and faulty-node replacement, staying up between jobs. Where ECS and EKS run application containers, HyperPod runs distributed training (#924).
AWS.SageMaker.Cluster
provisions the fleet. The default orchestrator is Slurm — an S3
lifecycle script, an execution role, and instance groups:
const cluster = yield* AWS.SageMaker.Cluster("TrainingCluster", { instanceGroups: { controller: { InstanceType: "ml.t3.medium", InstanceCount: 1, ExecutionRole: role.roleArn, LifeCycleConfig: { SourceS3Uri: script.sourceS3Uri, OnCreate: script.onCreate, }, }, },});Instance groups reconcile in place: change a count or add a group
and the cluster updates; remove one and it is deleted from the
cluster. Jobs are submitted with sbatch over SSM — every node
is an SSM target.
Pass orchestrator: { Eks } and the fleet’s nodes join an EKS
cluster you provide. From there, workloads are ordinary
Kubernetes objects — and
AWS.EKS.Job and
Deployment opt onto HyperPod
nodes with the hyperpod prop. The instance-group keys carry
through the cluster’s attributes as types, so a typo’d group name
is a compile error:
const train = yield* AWS.EKS.Job( "Train", { cluster: eks, main: import.meta.url, hyperpod: { instanceGroup: hyperpod.instanceGroups.workers }, }, Effect.gen(function* () { return { run: Effect.gen(function* () { // training logic; bindings land IAM on pod identity }), }; }),);Task governance arbitrates the fleet between teams:
ClusterSchedulerConfig
sets priority classes and
ComputeQuota reserves
per-team capacity (Kueue under the hood). A workload submits
through governance by passing the quota resource:
hyperpod: { instanceGroup: hyperpod.instanceGroups.workers, quota, // → hyperpod-ns-research + queue label priorityClass: "training",},Docs: HyperPod. The full working stack
(both orchestrators, governance, every workload tier) is
examples/aws-hyperpod.
Worker bundling fixes
Section titled “Worker bundling fixes”Two bundling bugs could break a deployed Worker even though the deploy succeeded. Both are fixed.
Hono/Express-style route registrations were stripped from the
bundle (#952).
purePlugin annotated top-level calls like app.get("/", handler) as pure, and under minification that annotation is a
deletion instruction — so every request 404’d. Statement-position
calls are now only annotated in packages that explicitly declare
sideEffects: false, and never in entry modules.
Cross-chunk evaluation order is now correct
(#940).
Rolldown could split top-level initializers (e.g. Drizzle
pgTable schemas) into a chunk that ran before its dependencies,
failing Cloudflare startup validation with Cannot access 'a' before initialization. strictExecutionOrder is now on by
default, preserving ESM semantics across chunk boundaries.
The same PR opens up per-Worker control of chunking: build
forwards rolldown output options and preserveEntrySignatures:
Cloudflare.Worker("Api", { main, build: { output: { codeSplitting: { groups: [{ name: "auth", test: "packages/(schema|auth)/" }], }, }, },});Destroy and nuke converge in one pass
Section titled “Destroy and nuke converge in one pass”Destroying a stack with a VPC-attached Lambda used to strand
subnets and security groups on DependencyViolation, forcing
repeated destroy runs
(#937). The
cause: Lambda’s Hyperplane ENIs linger in the VPC for many
minutes after the function is deleted, and AWS’s own reaper can
take 20+ minutes to clear them. Subnet and security-group deletes
now identify detached Lambda ENIs and delete them directly, so
one destroy removes everything.
alchemy unsafe nuke gets the same treatment
(#950):
--independentretries each delete on its own capped backoff instead of a shared barrier, so one hanging delete only ever stalls itself.- Providers declare which resource types their cloud-side teardown consumes (a HyperPod cluster deletes its ENIs by assuming its IAM role inside its VPC), and nuke deletes in topologically-ordered waves so a role is never deleted out from under an in-flight cluster teardown.
Also in this release
Section titled “Also in this release”_redirectsand_headersnow reach Cloudflare (#928) — the files were read and hashed but never sent, so redirect and header rules were silently dropped. They now apply in deploys, no-op redeploys, andalchemy dev.- Workflows under
alchemy dev: pausing a workflow no longer reportserrored(#934), and workflow classes export correctly in vite dev (#933). Docker.ContainersupportslabelsandstopTimeout(#931) — enabling Traefik-managed routing in a remote Docker context. Thanks Gerbuuun!alchemy/Test/Vitestis restored (#947) — the internal move to alchemy-test accidentally removed the public vitest harness that shipped through beta.63.- Branded primitives stay opaque in Outputs
(#941) — a
string & Brand<"UserId">Action output is nowOutput<UserId>instead of exploding into anObjectExprover every string method. - SQL fragment helpers compose on wrapped clients
(#951) —
sql`INSERT INTO users ${sql.insert(row)}`and nestedsql.and/sql.ornow replay against the resolved client, with new live test suites covering the fullSqlClientsurface on D1 and Postgres. - The alchemy-test plain reporter prints a
[done/total]progress counter per test and a failed-test list at the end of the run.