mirror of
https://github.com/hanzoai/tasks.git
synced 2026-10-04 02:04:03 +00:00
## What Adds an architecture doc for the worker commands framework — how commands flow from history through matching to workers, and how to add new command types. --------- Co-authored-by: Sean Kane <[email protected]> Co-authored-by: Hanzo Dev <[email protected]>
3.3 KiB
3.3 KiB
Worker Commands
Worker commands are server-initiated instructions sent to workers via Nexus. Each worker process has a dedicated control task queue that it polls via Nexus RPC. A single control queue serves one or more workers running within the same process. This enables the server to push actions to workers without relying on heartbeats or long-poll cycles.
To route a command, the server needs to know the target worker's control queue. For commands that target activities, this information is stored directly in the mutable state (ActivityInfo) when the activity was dispatched to the worker.
graph LR
subgraph History
A[Create Task] -->|1| C[Outbound Queue]
C -->|2| D[Dispatch]
end
subgraph Matching
E[Control Queue]
end
D -->|3| E
E -->|7| D
E ~~~ Worker
subgraph Worker
G[Poller] -->|5| F[Execute]
end
G -.->|4| E
F -.->|6| E
History
- Create Task -- The server decides whether to initiate a worker command based on a state change (e.g., a user requesting activity cancellation). The trigger logic creates one or more
WorkerCommandprotos and callsGenerateWorkerCommandsTasks, which persists them as an outbound task. Serialization is command-agnostic (task_serializers.go). - Outbound Queue -- The outbound queue executor picks up the task and invokes the dispatcher configured in
Execute. - Dispatch -- The
dispatchersends aDispatchNexusTaskRPC to matching. This is synchronous — matching holds the request until a worker responds or the request times out.
Matching
- Control Queue -- Matching holds the command on the control queue until a worker polls it. If no worker is polling, the request times out. There is currently no way to distinguish a permanently gone worker from a temporarily slow one, so the dispatcher simply retries up to a maximum number of attempts before dropping the task. This is acceptable because worker commands are best-effort.
Worker
- Poller -- The worker's poller picks up the command from the control queue.
- Execute -- The worker executes the command and sends the response back to matching.
Matching
- Response -- Matching forwards the response back to the dispatcher in history.
Adding a new command
- Define the proto -- Add a new variant to
WorkerCommandinmessage.proto(api repo). - Add a trigger -- Add server-side logic to detect the condition, create the command, and call
GenerateWorkerCommandsTasks(seetask_generator.go). - Handle in the SDK -- Add a handler for the new command variant in the SDK's worker command executor.