Repository navigation
Conversation
Alchemy had no state store for Google Cloud Storage. `GCP.state()` stores
state as JSON objects in a bucket, laid out like the S3 store, and locks
each (stack, stage) so two deploys cannot interleave writes.
- The lock is an object at `{prefix}__locks__/{stack}/{stage}`, created
with `ifGenerationMatch=0`. Contention fails immediately with
"another deploy holds the GCS state lock", as with postgresState().
- The holder refreshes the lock's expiry every 20 seconds (60 second TTL)
and deletes it on close. Both writes match the generation it created.
- A crashed deploy's lock expires; the next deploy deletes exactly the
expired version (generation + metageneration match) and takes over.
- The holder stops 15 seconds before its lock would expire, and reports
the lock lost when a refresh finds another generation.
- A missing bucket is created with versioning, uniform bucket-level
access and public access prevention. Existing buckets are not changed.
ObjectMedia gains `create`, a create-if-absent upload that fails with
`ObjectAlreadyExists` on 412.
duailibe
marked this pull request as ready for review
October 16, 2026 08:30
Contributor
|
Install the packages built from this commit: alchemypnpm install https://pkg.alchemy.run/alchemy/pr:2303:5b8dd23@alchemy.run (6)pnpm install https://pkg.alchemy.run/@alchemy.run/better-auth/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@alchemy.run/cloudflare-runtime/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@alchemy.run/frontend-frameworks/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@alchemy.run/node-utils/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@alchemy.run/floci/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@alchemy.run/pkg/pr:2303:5b8dd23Transitive Dependencies (19)pnpm install https://pkg.alchemy.run/@distilled.cloud/acme/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/aws/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/axiom/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/cloudflare/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/core/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/doppler/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/fly-io/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/gcp/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/hetzner/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/iceberg/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/infisical/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/neon/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/planetscale/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/prisma/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/railway/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/stripe/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/turso/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/zerossl/pr:2303:5b8dd23pnpm install https://pkg.alchemy.run/@distilled.cloud/github/pr:2303:5b8dd23Published |
Contributor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Alchemy has no state store for Google Cloud Storage, so a GCP-only team has to keep its state in S3, R2 or Postgres.
This adds
GCP.state(). It stores state as JSON objects in a bucket, with the same layout as the S3 store:Each
(stack, stage)is locked so two deploys of the same stage cannot interleave writes, like theAWS.state()lease from #2145. It uses GCS generations instead of ETags:ifGenerationMatch=0. If another deploy holds it, the operation fails right away with "another deploy holds the GCS state lock", aspostgresState()does.__locks__/instead of the stage directory, so a crashed deploy's lock never keeps a deleted stage inlistStages.If the bucket is missing, the store creates it with versioning, uniform bucket-level access and public access prevention. It leaves an existing bucket's settings unchanged.
GCP.Storage.ObjectMediagets a newcreatemethod that uploads an object only if none exists. It fails withObjectAlreadyExistson 412. The typed 412 onobjects.deleteandobjects.patchcomes from alchemy-run/distilled#877.CI doesn't run the GCP live tests, so I ran
test/GCP/StateStore/State.test.tsagainst a personal GCP project. All 4 cases pass and leave no buckets behind.