graph { graph [engine:dot rankdir:TD clusterize:false applyCss:dark intention:full] pattern__orchestrator -> pattern__orchestrator__experimental [reverse: false] pattern__orchestrator -> pattern__orchestrator__Recommended_minimal_clean_setup__3_queues_ [reverse: false] pattern__orchestrator__Recommended_minimal_clean_setup__3_queues_ -> pattern__orchestrator__Recommended_minimal_clean_setup__3_queues____pattern__orchestrator__queues [reverse: false] pattern__orchestrator *= pattern__orchestrator__Workflow_Orchestration [reverse: false] pattern__orchestrator *= pattern__orchestrator__problem__wait_for_bag_of_tasks [reverse: false] pattern__orchestrator__problem__wait_for_bag_of_tasks *= pattern__orchestrator__problem__wait_for_bag_of_tasks___pattern__orchestrator__Redis_Pub__Sub_notification [reverse: false] pattern__orchestrator__problem__wait_for_bag_of_tasks *= pattern__orchestrator__problem__wait_for_bag_of_tasks___pattern__orchestrator__join_barrier [reverse: false] pattern__orchestrator__problem__wait_for_bag_of_tasks___pattern__orchestrator__join_barrier *= pattern__orchestrator__problem__wait_for_bag_of_tasks___pattern__orchestrator__join_barrier___pattern__orchestrator__problem__wait_for_bag_of_tasks___pattern__orchestrator__Barrier_Counter_in_Redis__recommended_ [reverse: false] pattern__orchestrator__problem__wait_for_bag_of_tasks___pattern__orchestrator__join_barrier *= pattern__orchestrator__problem__wait_for_bag_of_tasks___pattern__orchestrator__join_barrier___pattern__orchestrator__problem__wait_for_bag_of_tasks___pattern__orchestrator__Barrier_via__completion_messages__queue [reverse: false] pattern__orchestrator *= pattern__orchestrator__problem__parallel_programs_ [reverse: false] pattern__orchestrator__problem__parallel_programs_ *= pattern__orchestrator__problem__parallel_programs____pattern__orchestrator__sharding [reverse: false] pattern__orchestrator *= pattern__orchestrator__conclusion [reverse: false] pattern__orchestrator__conclusion *= pattern__orchestrator__conclusion___pattern__orchestrator__state [reverse: false] pattern__orchestrator__conclusion *= pattern__orchestrator__conclusion___pattern__orchestrator__task_output [reverse: false] pattern__orchestrator__conclusion *= pattern__orchestrator__conclusion___pattern__orchestrator__completion_message [reverse: false] pattern__orchestrator [z: 9.5 @html: "
| pattern: orchestrator | ||||||||||
|
| experimental | |||
|
| Recommended minimal clean setup 3 queues | ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| This is the simplest clean design that gives you: | ||||||||||||||||||||||||
|
| queues | |||
|
| Workflow Orchestration RabbitMQ is only the transport; the orchestration logic lives in the program-json.This is a “Workflow Orchestration” (a.k.a. Saga Orchestration) pattern, a classic Saga orchestration where every “step” is either: | ||||
| ||||
| Orchestrated Workflow with Barrier Synchronization | ||||
|
| problem: wait for bag of tasks | |||
|
| Redis Pub/Sub notification | ||
| ||
| When you publish the parallel tasks: Set counter: SET barrier:<wf>:<step> N Workers, when done: DECR barrier:<wf>:<step> If result == 0 → PUBLISH barrier:done "<wf>:<step>" Orchestrator waits: redisSub.subscribe("barrier:done"); redisSub.on("message", (channel, msg) => { const 【wf, step】 = msg.split(":"); continueWorkflow(wf, step); }); ✅ zero polling ✅ instant reaction ✅ very scalableThis is the cleanest. |
| join barrier |
| Barrier Counter in Redis recommended Simple, robust, works great with RabbitMQ.How it works: | |||
| |||
| Why this is best: | |||
| |||
| Very easy in Node.js + STOMP |
| Barrier via “completion messages” queue RabbitMQ-only solution. Pattern: | |||
| |||
| Cons: | |||
|
| problem: parallel programs? | |||
| |||
| You said: | |||
| |||
| You want maximum simplicity, so:✅ Choose Option A: multiple orchestrator queuesYou only need two:/queue/orchestrator.fast /queue/orchestrator.slowThen route based on workflow type:const destination = workflow.type === 'fast' ? '/queue/orchestrator.fast' : '/queue/orchestrator.slow'Each queue has its own orchestrator consumer.✅ Fast workflows never wait behind slow ones ✅ No complexity ✅ No risk ✅ Perfect isolation |
| sharding Multiple orchestrator queues, each one handles many workflows, but each workflow stays in exactly one shard based on hash(workflowId)% N. Gives you isolation, parallelism, and ordering with bounded queue count. |
| conclusion | ||||
|
| state | |||||||
| |||||||
/program:id/plan /program:id/plan/step:0 /program:id/outout/step:0 /program:id/plan/step:1/bag:0 /program:id/output/step:1/bag:0 | |||||||
|
| task output | ||
|
| completion message | ||||||||||||||
|