Skip to main content
Use this when a step is heavy, must run next to a private resource (a database, a GPU host, an internal network) or should not compete with the engine for CPU and memory. The server that admits and tracks runs is the control plane. It still sees every message of a placed node, so placement moves the work, not the data. Prerequisites:
  • A Plus build (AGPL-3.0-only) with the workers module: -Pyukta.workers=true. The release binaries and the Docker image do not include it. See Licensing and editions.
  • The same build on the control plane and every worker, and the plugin types a worker will run built into that worker.
  • A long random token.
A native binary fixes its role when you build it. Build it with -Pyukta.workers.native=control-plane or -Pyukta.workers.native=worker. With the archive (jar) build, the settings choose the role.

Steps

1

Build with workers

Without the switch, a workflow that places a node fails to prepare with an error that names it.
2

Configure the control plane

The control plane is the server that has yukta.workers.token and no yukta.workers.control-plane:
This opens a second port, 7000, for workers. Workers connect out to it, so a worker needs no inbound port.
3

Secure the connection

Without TLS the token, node configurations and payloads cross the network in clear text. A control plane with no SSL bundle, or a worker whose control plane is not on its own machine and has no bundle, refuses to start unless you set yukta.workers.allow-insecure=true. Use that only on a network you trust.For mutual TLS, give the control plane a certificate and require a client certificate:
Give each worker its own certificate in a bundle that the worker names with yukta.workers.ssl-bundle (next step). The worker checks the control plane’s host name against its certificate.
4

Start a worker

A worker is a full Yukta process. Its settings:
yukta.workers.id is required. A worker with an empty yukta.workers.plugin-types runs nothing, so list every type it may run. When you run several workers on one machine, give each its own server.port. The defaults for pools (default), capacity (4) and the other settings are in Configuration reference.
5

Place a node

Add placement to the node’s engine object. A placement without pool uses the pool default. This node calls an internal service on a worker in private-net, with up to three attempts:
Only processors can be placed. SESSION_MEMORY, KV_STORE, WAIT_FOR_SIGNAL and SUB_WORKFLOW keep state on the control plane and refuse a placement. Triggers and terminals always run locally.

Verify it worked

List the workers the control plane knows:
Each entry shows the worker’s id, pools, plugin types, capacity, used slots, whether it is draining, and when its lease ends. Start the workflow with the placed node and read the node’s result. The gauges yukta.workers (connected workers) and yukta.worker.slots (free slots) show capacity on the metrics endpoint. If no worker qualifies, the attempt fails at once with “No connected worker in pool ‘private-net’ can run HTTP_REQUEST right now”. The error is retryable, so the node’s retry policy applies. A worker qualifies when it is connected, not draining, serves the pool, lists the plugin type and has a free slot.

Variations that matter

  • A secret per worker. Give the control plane yukta.workers.tokens.<worker-id>=<secret> for each worker (write yukta.workers.tokens[my.id] when the id has dots). As soon as one is set, only the listed workers are admitted, and the shared token stops working. To remove one compromised worker, delete its entry and restart the control plane.
  • Several control planes (high availability). Set yukta.workers.control-plane to every server, comma separated. A standby refuses the worker with “this server is not the leader”. See Run highly available.
  • Rolling restart of workers. A worker that stops tells the control plane it is draining and waits up to yukta.workers.drain-timeout (30 seconds by default) for running attempts. Anything still running fails and the engine retries it on another worker. A worker that loses the control plane reconnects with a pause that grows from 1 to 30 seconds.
  • Upgrade together. A worker that registers with another protocol version is refused and gets no jobs. Upgrade the control plane and the workers to the same release.
  • Make placed steps safe to repeat. Delivery is at least once. If a worker dies after an effect and before the attempt completes, the effect can happen twice. Use the message id as an idempotency key.
  • Configure workers like the server. A plugin runs inside the worker process, so the worker’s own allow-lists apply (commands, hosts, variables, secrets). See Secure the server.
What works differently on a worker: run budgets and rate limits (for example for LLM_CALL) are counted inside each worker, not for the whole run. Live log lines written on the worker do not reach the run’s log stream. Messages cross as plain JSON values.