From 51532c5256ee6e30470bd6b1312b25af36673bd9 Mon Sep 17 00:00:00 2001 From: Alex K Date: Wed, 8 Jul 2026 13:47:39 -0400 Subject: [PATCH] [wrangler] Handle queue bindings in remote dev --- .changeset/silent-queues-jam.md | 7 ++++ .../startDevWorker/ConfigController.test.ts | 40 +++++++++++++++++++ .../RemoteRuntimeController.test.ts | 36 +++++++++++++++++ .../startDevWorker/RemoteRuntimeController.ts | 14 ++++++- 4 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 .changeset/silent-queues-jam.md diff --git a/.changeset/silent-queues-jam.md b/.changeset/silent-queues-jam.md new file mode 100644 index 0000000000..c87dde953c --- /dev/null +++ b/.changeset/silent-queues-jam.md @@ -0,0 +1,7 @@ +--- +"wrangler": patch +--- + +Allow `wrangler dev --remote` to start when queue producer bindings are configured + +Queue bindings are still unsupported in legacy remote dev mode, but Wrangler now omits them from remote preview uploads after warning. This lets unrelated routes keep working instead of returning 500 errors for the whole dev session. diff --git a/packages/wrangler/src/__tests__/api/startDevWorker/ConfigController.test.ts b/packages/wrangler/src/__tests__/api/startDevWorker/ConfigController.test.ts index 640d7931ff..e9918b43b1 100644 --- a/packages/wrangler/src/__tests__/api/startDevWorker/ConfigController.test.ts +++ b/packages/wrangler/src/__tests__/api/startDevWorker/ConfigController.test.ts @@ -317,4 +317,44 @@ describe("ConfigController", () => { expect(warningCount).toBe(1); }); + + it("should warn when queues are configured in remote dev mode", async ({ + expect, + }) => { + await seed({ + "src/index.ts": dedent /* javascript */ ` + export default { + fetch() { + return new Response("hello world") + } + } + `, + "wrangler.toml": dedent /* toml */ ` + name = "my-worker" + main = "src/index.ts" + compatibility_date = "2024-06-01" + + [[queues.producers]] + binding = "QUEUE" + queue = "test-queue" + `, + }); + + const event = bus.waitFor("configUpdate"); + await controller.set({ + config: "./wrangler.toml", + dev: { + remote: true, + auth: { + accountId: "some-account-id", + apiToken: { apiToken: "some-api-token" }, + }, + }, + }); + await event; + + expect(std.warn).toContain( + "Queues are not yet supported in wrangler dev remote mode." + ); + }); }); diff --git a/packages/wrangler/src/__tests__/api/startDevWorker/RemoteRuntimeController.test.ts b/packages/wrangler/src/__tests__/api/startDevWorker/RemoteRuntimeController.test.ts index 16973da46d..7acb252672 100644 --- a/packages/wrangler/src/__tests__/api/startDevWorker/RemoteRuntimeController.test.ts +++ b/packages/wrangler/src/__tests__/api/startDevWorker/RemoteRuntimeController.test.ts @@ -158,6 +158,42 @@ describe("RemoteRuntimeController", () => { vi.mocked(getAccessHeaders).mockResolvedValue({}); }); + describe("unsupported queue bindings", () => { + it("should omit queue producer bindings from remote preview uploads", async ({ + expect, + }) => { + const { controller, bus } = setup(); + const config = makeConfig({ + bindings: { + QUEUE: { + type: "queue", + queue_name: "test-queue", + }, + KV: { + type: "kv_namespace", + id: "test-kv-namespace", + }, + }, + }); + const bundle = makeBundle(); + + controller.onBundleStart({ type: "bundleStart", config }); + controller.onBundleComplete({ type: "bundleComplete", config, bundle }); + await bus.waitFor("reloadComplete"); + + expect(createRemoteWorkerInit).toHaveBeenCalledWith( + expect.objectContaining({ + bindings: { + KV: { + type: "kv_namespace", + id: "test-kv-namespace", + }, + }, + }) + ); + }); + }); + describe("stale bundle bail-out", () => { it("should skip stale bundles and only reload once for rapid updates", async ({ expect, diff --git a/packages/wrangler/src/api/startDevWorker/RemoteRuntimeController.ts b/packages/wrangler/src/api/startDevWorker/RemoteRuntimeController.ts index cdfc1dfd3d..b04dc3651d 100644 --- a/packages/wrangler/src/api/startDevWorker/RemoteRuntimeController.ts +++ b/packages/wrangler/src/api/startDevWorker/RemoteRuntimeController.ts @@ -35,11 +35,21 @@ import type { ReloadCompleteEvent, ReloadStartEvent, } from "./events"; -import type { Bundle, StartDevWorkerOptions, Trigger } from "./types"; +import type { Binding, Bundle, StartDevWorkerOptions, Trigger } from "./types"; import type { Route } from "@cloudflare/workers-utils"; type CreateRemoteWorkerInitProps = Parameters[0]; +function getRemotePreviewBindings( + bindings: StartDevWorkerOptions["bindings"] +): Record { + return Object.fromEntries( + Object.entries(bindings ?? {}).filter( + ([, binding]) => binding.type !== "queue" + ) + ); +} + export class RemoteRuntimeController extends RuntimeController { #abortController = new AbortController(); @@ -156,7 +166,7 @@ export class RemoteRuntimeController extends RuntimeController { assets: props.assets, legacyAssetPaths: props.legacyAssetPaths, format: props.format, - bindings: props.bindings, + bindings: getRemotePreviewBindings(props.bindings), compatibilityDate: props.compatibilityDate, compatibilityFlags: props.compatibilityFlags, });