Skip to content

fix(cloudflare): name queues after the Worker so environments don't share them - #597

Merged
Brooooooklyn merged 2 commits into
mainfrom
fix/queue-name-scope
Oct 26, 2026
Merged

Brooooooklyn merged 2 commits into
mainfrom
fix/queue-name-scope

Conversation

@Brooooooklyn

Copy link
Copy Markdown
Member

Fixes #547.

Cloudflare queue names are unique per account. void deploy --platform cloudflare used the bare name from queues/, so two Workers of one app (staging and production) in one account bound the same queue and fought over its single consumer.

queues/jobs.ts, deployed as Worker app-staging

code, binding, types, vp dev     →  "jobs"              (unchanged)
Cloudflare queue                 →  "app-staging-jobs"  (new)
hosted platform, previews, plain `vite build`  →  unchanged

How a deploy picks each name

Preflight reads the account before provisioning or building:

1. "<worker>-jobs" exists and this Worker consumes it  → "<worker>-jobs"
2. "jobs" exists and this Worker consumes it           → keep "jobs" (prints a note)
3. otherwise                                           → "<worker>-jobs" (created if missing)

stop before anything is created when:
  - the chosen queue is consumed by another Worker (or an HTTP pull consumer)
  - a new queue's full name is over 63 characters (no silent trimming)
  - "<worker>-jobs" is also a file in queues/ (e.g. jobs + app-jobs in Worker app)
  - the queue or its consumer list can't be read
  • <worker> is the Worker name in resource-name form, as for R2 and KV (my_app → my-app-jobs). It is not trimmed, so my-long-app-staging and my-long-app-production can't collide.
  • Rule 2 keeps already-deployed apps on their queue and its backlog. Cloudflare's consumer list is the record, not void.lock.json, which every Worker deploying from the checkout shares.

The #547 repro, as tested:

account: "jobs" consumed by app-production
deploy app-staging     → app-staging-jobs (created)   staging stops feeding production
deploy app-production  → jobs (kept)                   backlog kept

Where the chosen names go

preflight ── desired.queueNames {jobs: "app-staging-jobs"}
   │
   ├─ native build (VOID_CLOUDFLARE_QUEUE_NAMES, set only for the deploy build)
   │     ├─ wrangler producers/consumers
   │     └─ route table: exact { cloudflare name → handler } map
   ├─ framework apps: root wrangler config (a producer Void wrote earlier moves in place;
   │                  the old consumer is detached) + wrapper with the same exact map
   └─ artifact check: emitted queue names must equal the chosen ones

The generated Worker now matches deploy names exactly. The old -name suffix match would send app-staging-jobs to queues/staging-jobs.ts when both jobs and staging-jobs exist. Without a deploy map (dev, preview, hosted), the resolver output is byte-for-byte the same as before.

queues.info now also returns each queue's consumers, read from the same account queue list. That costs no extra API calls. An app with no queues/ makes no queue calls (covered by a test).

Tests

  • queue-cloudflare-names.test.ts: naming rules, the env map reader, and the exact resolver (both wrong-handler layouts, plain names still match, unknown names fail).
  • cloudflare-deploy.test.ts, new queue-naming group: fresh account, kept plain queue, kept scoped queue, the Queue names aren't scoped per Worker/environment, so staging and production collide in one Cloudflare account #547 repro, two Workers in a new account, another Worker's consumer, an HTTP pull consumer, a 64-character name, the jobs + app-jobs clash, a my_app Worker, unreadable and killed probes, --provision, no queues, and an ambient map dropped.
  • wrangler.test.ts: a Void-written framework producer moves to the new name and the old consumer is queued for removal. A producer the user wrote still throws.
  • wrapper.test.ts, cloudflare-operation-process.test.ts: the framework wrapper's exact map, and consumer parsing (including ambiguous shapes, which leave the list unread).
  • integration/cloudflare-deploy-build.test.ts: a real kitchen-sink deploy build emits void-kitchen-sink-demo-queue and the exact map, and still passes the artifact check.
  • Mutation checks: each guarded line was broken in turn (13 in all), and each break made a test fail.
  • vp run check, vp fmt, vp lint, vp run test --base origin/main and one full vp test run pass.

An independent review in a separate worktree confirmed 4 defects in the first commit, all fixed in the second: a _ Worker name, the shared-name clash, the docs' move steps, and loose consumer parsing.

Choices to check

  • Whoever consumes a bare queue keeps it. If staging took over jobs earlier, staging keeps jobs and production moves to app-production-jobs. The docs explain how to move off a kept queue.
  • No void.config.ts mapping. The issue offered "suffix with the Worker name" or "a config mapping". This PR does the first. A mapping would add public config this bug doesn't need.
  • batch.queue on direct deploys is the Cloudflare name (app-staging-jobs), as Cloudflare documents. The hosted platform's native path already exposes prefixed names, and framework handlers must get the original MessageBatch (see packages/void/AGENTS.md).
  • An unreadable queue now stops the deploy. Before, an unclear probe let the deploy continue. Now a wrong guess could move a consumer, so the deploy stops instead.
  • The jobs + app-jobs clash in Worker app stops even an app that deployed before this change. Nothing says which queue an existing app-jobs belongs to.

🤖 Generated with Claude Code

Brooooooklyn and others added 2 commits October 26, 2026 19:25
…hare them

Cloudflare queue names are unique per account, and `void deploy --platform
cloudflare` used the bare name from `queues/`. Two Workers from one app,
such as staging and production, bound the same queue and fought over its
single consumer.

Deploys now use `<worker>-<name>`. A queue the Worker already consumes keeps
its name, so deployed apps keep their queue and its backlog, and a queue
another Worker consumes stops the deploy before the build. The build gets
the chosen names, and the generated Worker matches them exactly, since a
`-name` suffix can pick the wrong queue. Dev, previews, plain builds and the
hosted platform keep plain names.

Fixes #547

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Build the queue prefix from the Worker name in resource-name form, as R2
  and KV do, so a Worker named `my_app` gets `my-app-jobs` instead of a
  name Cloudflare rejects.
- Stop the deploy when one queue's Worker-named queue is another file in
  queues/ (`jobs` and `app-jobs` in Worker `app`); nothing says which queue
  an existing `app-jobs` belongs to.
- Read queue consumers with the same identity rules as consumer removal.
- Docs: say messages sent while moving off an old queue stay in it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Brooooooklyn

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-26T11:47:10.036426Z acb84cd Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: acb84cdba7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Brooooooklyn
Brooooooklyn merged commit 7cbb16e into main Oct 26, 2026
20 checks passed
@Brooooooklyn
Brooooooklyn deleted the fix/queue-name-scope branch October 26, 2026 12:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Queue names aren't scoped per Worker/environment, so staging and production collide in one Cloudflare account

1 participant