diff --git a/.changeset/silent-workflows-tap.md b/.changeset/silent-workflows-tap.md new file mode 100644 index 0000000000..4244690cd3 --- /dev/null +++ b/.changeset/silent-workflows-tap.md @@ -0,0 +1,8 @@ +--- +"miniflare": patch +"wrangler": patch +--- + +Fix local Workflow startup when compatibility flags include `experimental` + +Miniflare now deduplicates compatibility flags for the internal Workflow engine service. This prevents `wrangler dev` from failing with `Compatibility flag specified multiple times: experimental` when the user's Worker already enables that flag. diff --git a/packages/miniflare/src/plugins/workflows/index.ts b/packages/miniflare/src/plugins/workflows/index.ts index 37372e8cf8..2f2de132dc 100644 --- a/packages/miniflare/src/plugins/workflows/index.ts +++ b/packages/miniflare/src/plugins/workflows/index.ts @@ -119,10 +119,9 @@ export const WORKFLOWS_PLUGIN: Plugin< ), worker: { compatibilityDate: "2024-10-22", - compatibilityFlags: [ - "experimental", - ...(workflow.compatibilityFlags ?? []), - ], + compatibilityFlags: Array.from( + new Set(["experimental", ...(workflow.compatibilityFlags ?? [])]) + ), modules: [ { name: "workflows.mjs", diff --git a/packages/miniflare/test/plugins/workflows/index.spec.ts b/packages/miniflare/test/plugins/workflows/index.spec.ts index 33b1f0ee2c..56061c1fb7 100644 --- a/packages/miniflare/test/plugins/workflows/index.spec.ts +++ b/packages/miniflare/test/plugins/workflows/index.spec.ts @@ -22,6 +22,36 @@ export class MyWorkflow extends WorkflowEntrypoint { }, };`; +test("starts Workflows with user-provided experimental compatibility flag", async ({ + expect, +}) => { + const tmp = await useTmp(); + const mf = new Miniflare({ + name: "workflow-compatibility-flags-worker", + compatibilityDate: "2024-11-20", + modules: true, + script: WORKFLOW_SCRIPT(), + workflows: { + MY_WORKFLOW: { + className: "MyWorkflow", + name: "MY_WORKFLOW", + compatibilityFlags: [ + "nodejs_compat", + "experimental", + "enhanced_error_serialization", + ], + }, + }, + workflowsPersist: tmp, + }); + useDispose(mf); + + const res = await mf.dispatchFetch("http://localhost"); + expect(await res.text()).toBe( + '{"status":"complete","__LOCAL_DEV_STEP_OUTPUTS":["yes you are"],"output":"I\'m a output string"}' + ); +}); + test("persists Workflow data on file-system between runs", async ({ expect, }) => {