orchkaDocs

Operations

What a running deployment does on its own, and what you need to watch.

The two processes

WebWorker
RunsNext.js app, API, editorEvery workflow and node
Binds a portYes (PORT)No
Health check/api/healthNone — it serves no HTTP
Scale to zeroPossibleNever — it polls Redis for jobs

The worker receives no HTTP traffic ever, so any "sleep when idle" setting will stop it processing work entirely. Free tiers that spin down on inactivity cannot run it.

Health checks

/api/health returns 200 ok. It is liveness only and deliberately does not touch Postgres or Redis: a platform health check gates whether a deployment goes live, so probing dependencies turns a transient blip during rollout into a failed deploy and a rollback loop.

That means a green health check says the web process is up — not that the database is reachable.

Graceful shutdown

On SIGTERM the worker stops accepting new jobs, waits for in-flight ones to finish, then closes its queue connections. Order matters: the connections are closed only after the jobs using them have completed.

Give the worker a long stop timeout — 180 seconds is a reasonable starting point. Node concurrency is 5 workflows and 10 nodes, and AI and HTTP nodes can run for minutes. Many platforms default the grace period to zero, which turns SIGTERM straight into SIGKILL and drops running work.

Retention

Nothing expired the database before this existed. The worker runs one sweep daily, on the queue, in two stages:

WindowDefaultRemoves
ORCHKA_RETAIN_STEPS_DAYS30 daysStep detail and payloads
ORCHKA_RETAIN_EXECUTIONS_DAYS90 daysThe execution rows themselves

Step detail is bulky and short-lived; the run itself is cheap and worth keeping in the history list, so they expire separately. Deleting an execution cascades to its steps, payloads and dead letters.

Two things the sweep never touches:

  • Daily statistics (execution_stat). These have no link to executions precisely so the rollups behind the dashboard outlive the runs they summarise.
  • Executions with a pending dead letter. Sweeping one would erase an un-triaged failure before anyone saw it. Resolve or discard the dead letter first.

The credential audit log rides the execution window.

Logging

The worker logs structured JSON to stdout via pino. Every line emitted during a run carries the same executionId, workflowId and nodeId, so investigating an incident is one filter rather than a grep through interleaved runs.

{"level":30,"time":1788911772997,"workflowId":"cmp...","executionId":"cmt...",
 "nodeId":"x7m...","nodeName":"Cron Trigger","msg":"[Node 1/2] Executing Cron Trigger"}

LOG_LEVEL controls verbosity (default info).

Node input and output are not logged. They were once, which meant HTTP response bodies and AI output went to stdout on every node of every run. Payloads are visible in the execution viewer instead, where they are access-controlled.

There is no log aggregation built in — the process ships JSON and whatever runs it collects the output.

Redis is not a cache

BullMQ keeps in-flight job state and per-execution step history in Redis; steps are flushed to Postgres on completion and at periodic checkpoints. A Redis that loses data therefore loses running workflows.

  • Enable persistence (AOF, or at minimum snapshots). The local compose file sets appendonly yes with appendfsync everysec.
  • Set the eviction policy to noeviction. On an evicting policy Redis discards job data under memory pressure and runs disappear with nothing in the logs.

Cron schedules survive a Redis wipe: the worker reconciles them from Postgres at boot and re-arms anything missing. Only schedules explicitly stopped stay stopped.

What to watch

Nothing alerts on its own. The two worth wiring up:

  • Dead letters. Terminally failed nodes land in a table with a replay UI, and accumulate silently until someone looks. See Execution Reliability.
  • Worker liveness. It exposes no endpoint, so absence of log output is the signal that it has stopped.

Backups

Not configured by Orchka. Two things need them:

  • Postgres — workflows, credentials and history.
  • CREDENTIAL_ENCRYPTION_KEY — losing it makes every stored credential permanently unreadable, and there is no rotation path. A database backup without the key is not a restore.

On this page