- Observability → Pod stack trace dumps for live thread-stack diagnostics via
SIGUSR2. - Database configuration for DB pool sizing and timeouts.
- LLM options → Azure Vision for OCR provider timeouts, retries, and failover.
v1.12.6 to v1.13 streaq migration
v1.13 requires a healthy Redis-backed streaq deployment. Upgrade to the stable v1.12.6 release (not a prerelease) first and keep the legacy PostgreSQL queue workers running while streaq is validated and traffic drains. Streaq is opt-in on v1.12.6 patches: a routine install or upgrade that never setsWORKER_PROVIDER: STREAQ_LOCAL is not affected by anything below and
will not have its release blocked. The checks described here only activate
once you configure streaq, and they stay mandatory from that point on —
including for any later v1.12.6+ patch upgrade, not just the v1.13 cutover.
Configure v1.12.6 with a small, fixed streaq pool:
redis.enabled: true or supply REDIS_URL through env,
secretEnv, or envFrom. The v1.12.6 Helm post-upgrade check sends a real
ping task through both the io and cpu queues. The release fails if Redis
is unreachable, either worker is missing, or the values above are incomplete.
Before the v1.13 upgrade, run several representative /parse requests with
the request-scoped streaq canary enabled:
--timeout 10m for each Helm upgrade in this migration. The preflight Job
has a nine-minute deadline, including pod scheduling and up to six minutes for
worker health checks, so Helm’s five-minute default timeout is insufficient.
On v1.12.6, the health check is a post-upgrade hook that only runs once
streaq is configured: a failure marks the Helm release failed after its
resources are applied. Correct the reported topology or Redis issue and
rerun the upgrade, or roll back. The v1.13 check runs pre-upgrade, and
runs unconditionally, regardless of whether streaq was ever configured,
blocking resource changes when its prerequisites fail.
- Upgrade to v1.13 with
worker.enabled: true. The pre-upgrade check requires an installed release marker from v1.12.6 or a later v1.12 patch and repeats the live Redis worker round trips before changing resources. - Scale the streaq pools for production load, then set both the trainable and
non-trainable
*_STREAQ_*_ROLLOUT_RATIOvalues to1.0for parse, extract, split, edit, and pipeline. Keep the legacy worker enabled while existing PostgreSQL-queue work drains. At full parse cutover, asynchronous requests withuse_reducto_liteorreducto_lite.enabledare rejected because those modes require the legacy worker; the synchronous variants remain available because they run inline or route their base arm through streaq. - Poll
GET /drain_statusuntildrainedistrue. Then setworker.enabled: false,worker.priorityCount: 0, andgpuWorker.enabled: false. The Helm pre-upgrade check blocks this final apply unless the currently running HTTP deployment reports every effective rollout ratio as1.0and the live drain check passes. Ratios supplied viaenv,secretEnv, orenvFromare all read from that running process, so deploy the ratio change before the separate worker-disable apply.
created_at.
This drain check is not limited to the v1.13 cutover: once streaq is
configured, setting worker.enabled: false on any v1.12.6+ patch is treated
the same way — the apply is blocked unless every rollout ratio is 1.0 and
GET /drain_status reports drained. There is no earlier, unguarded way to
disable the legacy worker after streaq is armed.
Re-enable worker.enabled and restore the rollout ratios to roll back while
the v1.13 chart still contains the legacy worker templates.
Worker liveness probe
The DB-queue worker pods (reducto-worker, reducto-priority-worker, reducto-gpu-worker) ship with a Kubernetes liveness probe that restarts a pod only when it is stuck mid-processing, not when it is idle waiting for work.
How it works
- An asyncio
WorkerWatchdogtask runs alongside the worker’s job loops. - Every 5 seconds it writes a heartbeat file
/tmp/worker-statecontaining<unix_timestamp> <oldest_in_flight_task_age_seconds>. Idle workers emit-1for the age. - The kubelet runs
bin/worker-liveness.shas anexecprobe. The script fails (exit non-zero) and triggers a restart when either:- the heartbeat file itself is older than
WORKER_LIVENESS_WATCHDOG_STALE_SEC(event loop is wedged so the watchdog can’t tick); or - the oldest in-flight task age exceeds
WORKER_LIVENESS_STUCK_THRESHOLD_SEC(a real job has hung beyond the threshold).
- the heartbeat file itself is older than
- Idle workers always pass the probe. The watchdog ticks even with no work, and the age sentinel
-1is always treated as healthy.
/health endpoint because an HTTP server can keep returning 200 while the asyncio event loop is blocked on a syscall. The watchdog has to be alive to refresh the file, so the probe directly tests the thing we care about.
Helm configuration
Configure the probe viaworker.livenessProbe.* in your Helm values:
reducto-worker, reducto-priority-worker, and reducto-gpu-worker together.
Defaults
Environment variables
The Helm chart pipes the values above into env vars that the Python watchdog and shell probe both read, so the two stay in sync. You normally configure these via Helm, but you can override directly when running outside the chart:Disabling the probe
If you’re operating in a constrained environment that can’t run exec probes, or you’d rather rely on external orchestration, set:logfire.warn when tasks exceed 80% of the threshold. The probe just doesn’t trigger restarts.