You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When a workflow uses Effect.all(activities, { concurrency: N }) where N > 1 and each element is an Activity.make(...), the workflow completes successfully on first execution but deadlocks during durable replay (e.g. when the workflow engine re-executes the workflow to recover state).
Minimal reproduction pattern:
import{Activity,Workflow}from"@effect/workflow";import{Effect,Schema,Schedule}from"effect";constMyWorkflow=Workflow.make({name: "DeadlockRepro",payload: Schema.Struct({items: Schema.Array(Schema.String)}),success: Schema.String,execute: ({ items })=>Effect.gen(function*(){// Create an array of activities, one per itemconstactivities=items.map((item)=>Activity.make({name: `process:${item}`,success: Schema.String,error: Schema.String,execute: Effect.succeed(`done:${item}`),}));// This works with concurrency: 1, deadlocks with concurrency > 1 during replayconstresults=yield*Effect.all(activities,{concurrency: 3});returnresults.join(",");}),});
Steps to reproduce:
Execute the workflow with items: ["a", "b", "c", "d", "e"]
All 5 activities complete successfully on first execution
Trigger a replay (e.g. restart the workflow engine, or let durable execution recovery kick in)
During replay, the workflow hangs indefinitely — activities never resume
The same Effect.all({ concurrency: 3 }) pattern works perfectly outside of @effect/workflow (i.e. without Activity.make), confirming the issue is in the Activity replay mechanism interacting with concurrent suspension.
What is the expected behavior?
Effect.all(activities, { concurrency: N }) where N > 1 should work correctly both during first execution and during replay. Activities should be replayed from the durable log and the concurrent combinator should resume all branches.
What do you see instead?
The workflow hangs indefinitely during replay. No error is thrown, no timeout fires at the workflow level — the activities simply never complete. The workflow fiber appears to be suspended waiting for activity results that are never replayed.
With concurrency: 1 (sequential execution), the same workflow replays correctly.
Additional information
History:
Designed concurrency: 3 to match provider API rate limits
Upgraded to 0.16.0, restored concurrency: 3 — deadlock persisted during replay
Reverted to concurrency: 1 as workaround
Investigation (2026-01-30): Created a standalone test that runs the same provider layer stack (CredentialService + RateLimitedHttpClient + NotionProvider) with Effect.all({ concurrency: 3 }) but without any @effect/workflow or Activity machinery. Result: 14/14 pages fetched successfully in both sequential and concurrent modes. No hang. This confirms the service layer is not the cause — the deadlock is specifically in the Activity replay mechanism when combined with concurrent Effect.all.
Workaround: Use concurrency: 1 (sequential) for all Effect.all/Effect.forEach calls that wrap Activity.make. This avoids the deadlock but sacrifices throughput.
Related:#5876 (different symptom — unhandled error logging — but same @effect/workflow Activity area)
What version of Effect is running?
effect: 3.19.15@effect/workflow: 0.16.0@effect/platform: 0.94.2@effect/cluster: 0.56.1What steps can reproduce the bug?
When a workflow uses
Effect.all(activities, { concurrency: N })whereN > 1and each element is anActivity.make(...), the workflow completes successfully on first execution but deadlocks during durable replay (e.g. when the workflow engine re-executes the workflow to recover state).Minimal reproduction pattern:
Steps to reproduce:
items: ["a", "b", "c", "d", "e"]The same
Effect.all({ concurrency: 3 })pattern works perfectly outside of@effect/workflow(i.e. withoutActivity.make), confirming the issue is in the Activity replay mechanism interacting with concurrent suspension.What is the expected behavior?
Effect.all(activities, { concurrency: N })whereN > 1should work correctly both during first execution and during replay. Activities should be replayed from the durable log and the concurrent combinator should resume all branches.What do you see instead?
The workflow hangs indefinitely during replay. No error is thrown, no timeout fires at the workflow level — the activities simply never complete. The workflow fiber appears to be suspended waiting for activity results that are never replayed.
With
concurrency: 1(sequential execution), the same workflow replays correctly.Additional information
History:
concurrency: 3to match provider API rate limits@effect/workflow0.15.2 which included PR ensure no more Activites are attempted before suspending #5880 ("ensure no more Activities are attempted before suspending") — believed to fix thisconcurrency: 3— deadlock persisted during replayconcurrency: 1as workaroundInvestigation (2026-01-30): Created a standalone test that runs the same provider layer stack (
CredentialService+RateLimitedHttpClient+NotionProvider) withEffect.all({ concurrency: 3 })but without any@effect/workfloworActivitymachinery. Result: 14/14 pages fetched successfully in both sequential and concurrent modes. No hang. This confirms the service layer is not the cause — the deadlock is specifically in the Activity replay mechanism when combined with concurrentEffect.all.Workaround: Use
concurrency: 1(sequential) for allEffect.all/Effect.forEachcalls that wrapActivity.make. This avoids the deadlock but sacrifices throughput.Related: #5876 (different symptom — unhandled error logging — but same
@effect/workflowActivity area)