@@ -297,15 +297,52 @@ When the worker encounters this, it executes all steps within the `Promise.all`
297297concurrently. It waits for all of them to complete before proceeding. Each step
298298attempt is persisted individually as a ` step_attempt ` .
299299
300- ### 5.2. Workflow Concurrency
300+ ### 5.2. Worker Concurrency
301301
302302Workers are configured with a concurrency limit (e.g., 10). A worker will
303303maintain up to 10 in-flight workflow runs simultaneously. It polls for new work
304304only when it has available capacity. The Backend's atomic ` dequeue ` operation
305305(` FOR UPDATE SKIP LOCKED ` ) ensures that multiple workers can poll the same table
306306without race conditions or processing the same run twice.
307307
308- ### 5.3. Handling Crashes During Parallel Execution
308+ ### 5.3. Workflow-Run Concurrency
309+
310+ In addition to worker-slot concurrency, workflows can define a per-run
311+ concurrency policy in the workflow spec:
312+
313+ ``` ts
314+ defineWorkflow (
315+ {
316+ name: " process-order" ,
317+ concurrency: {
318+ key : ({ input }) => ` tenant:${input .tenantId } ` ,
319+ limit : ({ input }) => input .maxConcurrentOrders ,
320+ },
321+ },
322+ async ({ step }) => {
323+ // ...
324+ },
325+ );
326+ ```
327+
328+ ` key ` and ` limit ` can each be either static values (` string ` /` number ` ) or
329+ functions of the validated workflow input. They are resolved once when the run
330+ is created and persisted on the ` workflow_run ` .
331+ Resolved keys are stored verbatim; only empty/all-whitespace keys are rejected.
332+
333+ During claim/dequeue, a run is claimable only when the number of active leased
334+ ` running ` runs in the same bucket is below the run's ` limit ` . The bucket scope
335+ is:
336+
337+ - ` namespace_id `
338+ - ` workflow_name `
339+ - ` version ` (version-aware buckets)
340+ - ` concurrency_key `
341+
342+ ` pending ` , ` sleeping ` , and expired-lease ` running ` runs do not consume
343+ concurrency slots.
344+
345+ ### 5.4. Handling Crashes During Parallel Execution
309346
310347The ` availableAt ` heartbeat mechanism provides robust recovery. If a worker
311348crashes while executing parallel steps, its heartbeat stops. The ` availableAt `
0 commit comments