Ghouls

In plain words: Background workers

Partial 4 min read 11 glossary terms 10 connected pages
The short version written for the Snayu team

How queued jobs get picked up and pushed forward by background workers inside the one server process, and what happens to a job when it has to wait or the server dies.

Why read it: Read this before touching job execution, retries or anything that waits for approval: it explains which job states survive a crash.
  1. 1Each job has one official record (a Run) in the database; workers (Ghouls) only move it forward.
  2. 2Only one worker can claim a job delivery; duplicates and stale deliveries are skipped, and workflow jobs get no automatic retries.
  3. 3Waiting for approval saves a checkpoint so a later worker can resume; waiting for hardware does not survive a restart.

Partial Workers run today; full crash-safe resume and the Sandbox (Tomb) are not finished.

Words on this page, decoded click one for its card

Settings FolderStep MapMemory VaultJob RecordPauseEngine RoomWorkers
Where it sits in LychD

Workers Ghouls

Background workers that pick up queued jobs and push them forward.

It's like: Kitchen staff who take tickets off the rail and cook them.

Click a dot to open that part's card.

The original text Underlined words open their plain-English card.

Work is queued. The dead hand rises. The result returns.

A RunJob Record carries the canonical identity and lifecycle of admitted work. A GhoulWorker is the worker-task invocation that advances it. After a durable park, another GhoulWorker may carry the same RunJob Record forward with its InvocationJob Request, pinned PatternWorkflow, and retained Agent selection. Return rebuilds step dependencies, reacquires the grants it needs, and revalidates the recorded authority.

The living worker

The single Vessel owns two fixed SAQ worker loops, runs and rites. QueueConfig.separate_process=False keeps them in process; SAQConfig.use_server_lifespan=False leaves startup and shutdown to the application. Exactly one ASGI process is required while RunEventBus and the service graph remain process-local.

Queued work has no process isolation. A blocking GhoulWorker can block HTTP, and VesselEngine Room death destroys the live task and subscribers even when the broker retains its job.

Admission and claim

Admission starts in RunEngine.submit, which chooses the workflow and queue. RunLedger then mints the RunJob Record id and commits QUEUED, PatternWorkflow, IntentRequest, queue, priority, authority, and exact initial delivery in one transaction.

Some callers must retain their own material before publication. For those callers, delivery starts HELD and becomes PENDING only after retention succeeds. Otherwise it starts PENDING. The live channel opens and run:<run_id>:<enqueue_seq> publishes only after any required release.

Each failure keeps its own boundary:

Failure What remains true
Caller retention fails Only an exact unreleased held admission may be settled; compensation retry is bounded.
Broker publication fails The admitted RunJob Record and exact pending delivery remain for the startup/runtime relay.
Broker acceptance is ambiguous The idempotent delivery key and claim fence settle ownership.
Cancellation wins while publication is in flight The losing publisher aborts the late physical job.

PostgreSQL admission and broker publication are separate commits. Only perform_run executes the GraphStep Map: it claims exact (run_id, enqueue_seq) through QUEUED → RUNNING. A stale or duplicate delivery returns skipped. A missing workflow, changed PatternWorkflow, or missing resume checkpoint refuses execution after claim; execution never starts the IntentRequest over to fill the gap.

SAQ timeout=0 disables its generic wall clock. Graph, provider, and OrchestratorStage Manager deadlines still apply, and the live invocation refreshes a 120-second Run-job heartbeat. Workflow jobs have zero automatic SAQ retries.

Parks, terminal truth, and cancellation

A hardware wait keeps this GhoulWorker resident: AWAITING_HARDWARE returns in the same hop and cannot survive restart. A consent or delegated wait commits checkpoint and exact owner before entering AWAITING_CONSENT or AWAITING_DELEGATE. One later resume admission creates the next pending delivery in the same transaction; publication may follow. Stasis and return explains those thresholds.

For worker-owned DONE or FAILED settlement, the sequence is:

commit DONE / FAILED and exact delivery settlement
→ release context
→ delete stasis best-effort
→ publish the terminal event and drain its ordered Step writer chain
→ close the live channel

Once status commits, cleanup or evidence failure cannot revise it. Before settling failure, the worker must also contain correlated children. It retries transient containment failures; continuing uncertainty leaves the RunJob Record nonterminal for recovery. Claiming FAILED while correlated authority could still act would conceal an unresolved effect.

Before containment, the GhoulWorker checks its exact delivery generation under the same per-Run guard used for claims and park commits. A late failure therefore cannot cancel the next GhoulWorker's effects or undo a durable wait whose commit acknowledgement was lost.

Cancellation elects one writer, commits CANCELLING, and fences claims and delivery rotation. The elected generation may commit CANCELLED only after broker, delegate, and pending ConsentApproval Step containment acknowledge. A worker that sees its exact CANCELLING generation releases volatile ContextBriefing Pack for containment acknowledgement while keeping its checkpoint.

After CANCELLED commits, the engine handles terminal evidence and channel closure, then performs best-effort ContextBriefing Pack and checkpoint cleanup. Evidence failure still runs that cleanup. If containment remains uncertain, status stays CANCELLING. If completion already won, a new cancellation is a no-op.

RunEvent has bounded process-local replay. Non-token events copy to step best-effort; token deltas are live-only. The evidence class is durable_best_effort, not a transactional event outbox.

Death and reconciliation

A new process judges committed RunJob Record, delivery, checkpoint, ConsentApproval Step, and delegated-owner truth. Reanimation owns the state-by-state return: unsupported active work becomes FAILED / ghoul lost, exact durable waits may return, and missing or ambiguous required truth aborts PostgreSQL startup.

Startup repairs missing terminal evidence from canonical terminal RunsJob Records. If existing terminal evidence disagrees, required PostgreSQL startup aborts instead of overwriting it. Cancellation cleanup may still remove its checkpoint when evidence fails.

Lifespan-owned relays continue delivery, consent, and delegated-owner repair. While scanning forward, they retain every degraded page so a blocked owner cannot disappear behind a keyset cursor. Consent lookup and re-admission share one ten-second deadline per owner. A timeout keeps the wait or committed pending delivery and lets other owners progress. There is no same-boot worker-failure custody watchdog, public failed-Run retry, or workflow scheduler.

Workers owns claims and recovery; Graph owns checkpoints and terminal commits. Topology-A is Available; durable stasis and consent re-admission remain Partial.

The unbuilt worker

The designed TombSandbox would receive a narrow payload and workspace grant without model credentials or GraphStep Map authority. Its worker, queue, credentials, and sandbox do not exist; unsafe execution remains disabled.

The GhoulWorker may borrow the hand. It never inherits the Will.