Worker & dispatch
Worker, WorkerOptions, the dispatch source, and job lifecycle.
The worker package runs agent sessions as jobs. A Worker registers with a
DispatchSource, reports load, accepts/rejects offers, and runs each assigned
job. For the MVP the dispatcher is embedded in-process; the worker↔dispatch
boundary is message-passing, so it can be extracted later.
Worker
func New(opts WorkerOptions) (*Worker, error)
func (w *Worker) Run(ctx context.Context, source DispatchSource) error
func (w *Worker) Drain(ctx context.Context) error
func (w *Worker) ID() string
func (w *Worker) ActiveJobs() intRun registers the worker and processes jobs until ctx is cancelled — call it
once. Drain stops accepting new jobs and waits for running jobs and
accepted-but-unassigned reservations to finish.
WorkerOptions
| Field | Default | Notes |
|---|---|---|
Entrypoint | — (required) | func(ctx, *JobContext) error, run per job. |
OnRequest | accept-all | func(*JobRequest) error — accept/reject offers. |
Load | concurrency-based | func(LoadInfo) float64 — custom load reporting. |
MaxJobs | GOMAXPROCS | Concurrent job ceiling. |
LoadThreshold | DefaultLoadThreshold | Load at which the worker reports full. |
WorkerType | WorkerTypeRoom | Room (one job/room) or Publisher (one/publisher). |
StatusInterval / PingInterval | defaults | Reporting / heartbeat cadence. |
JobRunner | goroutine + recover | Job isolation seam (subprocess later). |
Telemetry | SDK default | Worker/job lifecycle spans. |
AgentName / Namespace / Version / Deployment | Registration identity. | |
Permissions | DefaultPermissions | Room-join permissions. |
JobContext
type JobContext struct {
Job Job
WorkerID string
URL string
Token string
}
func (c *JobContext) OnShutdown(fn func())Passed to the entrypoint. OnShutdown registers cleanup run in reverse order
when the job ends — use it to close the session and release resources.
DispatchSource
Run takes a DispatchSource — the control-plane connection that offers jobs.
For the single-binary MVP it's an embedded dispatcher; behind a LiveKit server
it's the server connection. The worker speaks a LiveKit-compatible protocol, so
the same worker runs under either.
The dispatcher itself is internal (embedded for the MVP). You interact with it
only through the DispatchSource you pass to Run. Dispatch supports an
optional WithDispatchTimeout ceiling; by default a dispatch is bounded by the
caller's context.
Boundaries
Cross-node job routing, worker reconnect/retry, and MigrateJob are deferred to
the LiveKit wire adapter. The coordinator provides shared registry/load/affinity
state but not cross-node routing — ingress is sticky and dispatch is local.
Related
- Guide: Deploy a worker
- Architecture · Scaling & load · Graceful drain