Skip to content

fix(cloudflare): use queue dev.id for consumer resource ID in local dev mode#1364

Open
xiaoyu2er wants to merge 1 commit intoalchemy-run:mainfrom
xiaoyu2er:fix/queue-consumer-id-collision
Open

fix(cloudflare): use queue dev.id for consumer resource ID in local dev mode#1364
xiaoyu2er wants to merge 1 commit intoalchemy-run:mainfrom
xiaoyu2er:fix/queue-consumer-id-collision

Conversation

@xiaoyu2er
Copy link
Contributor

Problem

In local dev mode, Queue resources return an empty string for id (Cloudflare API ID) since no remote API call is made. When a Worker has multiple eventSources, all QueueConsumers are derived as ${queue.id}-consumer which all resolve to "-consumer", causing concurrent Promise.all writes to the same state file.

This leads to:

  • Corrupted JSON state files (null bytes from concurrent writes)
  • Silently broken queue consumers — Worker HTTP endpoint responds normally but queue messages are never consumed
  • Persistent failures — every subsequent alchemy dev fails with SyntaxError: JSON Parse error

Fix

Use queue.dev.id (the resource ID, e.g. "email-queue") in local dev mode instead of queue.id (empty ""). The dev.id is always unique per queue and available in dev mode.

// Before: all consumers get ID "-consumer"
QueueConsumer(`${eventSource.queue.id}-consumer`, { ... });

// After: each consumer gets unique ID like "email-queue-consumer"
const queueId = options.local
  ? (eventSource.queue.dev?.id || eventSource.queue.id)
  : eventSource.queue.id;
QueueConsumer(`${queueId}-consumer`, { ... });

Reproduction

See #1363 for full details and a diagnostic script.

Quick summary: any Worker with 2+ eventSources in alchemy dev mode will have all queue consumers writing to the same -consumer.json state file.

@xiaoyu2er xiaoyu2er force-pushed the fix/queue-consumer-id-collision branch from e6c94ab to 11f6ae2 Compare March 16, 2026 06:51
@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 16, 2026

Open in StackBlitz

npm i https://pkg.pr.new/alchemy@1364

commit: f08822f

…ev mode

In local dev mode, Queue resources return an empty string for `id`
(Cloudflare API ID) since no remote API call is made. When a Worker
has multiple eventSources, all QueueConsumers were derived as
`${queue.id}-consumer` which all resolved to "-consumer",
causing concurrent Promise.all writes to the same state file.

This led to corrupted JSON state files and silently broken queue
consumers — the Worker HTTP endpoint would respond normally but
queue messages were never consumed.

Fix: use `queue.dev.id` (the resource ID, e.g. "email-queue") in
local dev mode, which is always unique per queue.

Fixes alchemy-run#1363
@xiaoyu2er xiaoyu2er force-pushed the fix/queue-consumer-id-collision branch from 11f6ae2 to f08822f Compare March 16, 2026 06:56
@xiaoyu2er xiaoyu2er marked this pull request as draft March 16, 2026 07:07
@xiaoyu2er xiaoyu2er marked this pull request as ready for review March 16, 2026 07:46
// all consumers colliding on the same "-consumer" resource ID.
// See: https://github.com/alchemy-run/alchemy/issues/1363
const queueConsumerId = options.local
? eventSource.queue.dev?.id || eventSource.queue.id
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't we want this the other way around?

const queueConsumerId = options.local
              ? eventSource.queue.id ?? eventSource.queue.dev?.id
              : eventSource.queue.id;

or if we know that the non-dev queue id is always going to be bad just

const queueConsumerId = options.local
              ? eventSource.queue.dev?.id
              : eventSource.queue.id;

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.

2 participants