Skip to main content
Noxus workers execute background tasks — workflow runs, knowledge-base ingestion, and agent conversations. The job queue lives in PostgreSQL. Workers poll it rather than consuming from a broker, which has two practical consequences:
  • Database connection pressure scales with worker replica count. Each pod opens its own connection pools. See connection pooling below.
  • Queue depth is directly observable in the database, which is what makes KEDA’s queue-driven autoscaling accurate — it reacts to actual backlog instead of waiting for CPU to rise after work has already been queued.
Redis is used for caching, distributed locks, and live-stream coordination — not as the job queue. Workers are configured through environment variables that control task routing, and the Helm chart supports defining multiple pools — each with its own Deployment, Service, autoscaler, and PodDisruptionBudget.

Task Routing

Queue Types (WORKER_SUBSCRIBE)

Each worker pool subscribes to one or more task types via the WORKER_SUBSCRIBE environment variable.
A single pool on the default all_but_kb has no consumer for knowledge-base ingestion — those jobs queue indefinitely with nothing to pick them up. Either add a kb pool or set your single pool to all.

Workspace Filtering

Workers can be scoped to specific workspaces using comma-separated ID lists: These filters combine with WORKER_SUBSCRIBE — a pool set to workerSubscribe: "flow" with workerSubscribeWorkspaces: "ws-abc,ws-xyz" processes workflow tasks for those two workspaces only. The pair is designed to be used together: give a noisy workspace a dedicated pool via workerSubscribeWorkspaces, and add the same IDs to the catch-all pool’s workerUnsubscribeWorkspaces so it keeps running everything else — including maintenance and system jobs — without competing for that workspace’s work.

Worker Pools

Define multiple pools under worker.pools in your Helm values. Each pool creates an independent Kubernetes Deployment.

Pool Configuration Reference

Basic Multi-Pool Example


Workspace Isolation

Use workerSubscribeWorkspaces and workerUnsubscribeWorkspaces to dedicate worker pools to specific workspaces. This is useful for:
  • Noisy-neighbor isolation — prevent one team’s heavy workloads from starving others
  • SLA tiers — dedicated capacity for priority workspaces
  • Data residency — pin certain workspaces to workers on specific nodes or in specific zones
The two variables are designed to be used as a pair. Giving a workspace a dedicated pool is only half the job: without excluding it from the catch-all pool, both pools compete for the same work.
This isolates load, not data. All pools share one database and one cluster; the tenant and workspace boundaries are enforced by the application, not by the infrastructure. If you need infrastructure-level separation between customers, run separate deployments.

Per-Pool Secrets

By default, all worker pools share the same Kubernetes Secret ({release}-app-env). When different pools need different environment variables — such as separate LLM API keys per tenant, different Redis databases, or pool-specific feature flags — use envSecretRef to layer an additional Secret on top.
Create the per-pool secret separately (or via External Secrets Operator):
The pool-specific secret is mounted after the shared one in envFrom, so its values take precedence for any overlapping keys.

Multi-Namespace Deployment

To run worker groups in different namespaces (e.g., for resource quotas or network policy isolation), deploy separate Helm releases that share the same backend infrastructure.
1

Deploy the primary release

The primary release deploys backend, frontend, and the default worker pool.
2

Deploy worker-only releases

For each additional namespace, disable all non-worker components and provide the same database/Redis credentials.
All worker releases must connect to the same PostgreSQL and Redis instances. Redis coordinates task distribution — workers in any namespace pick up tasks from their subscribed queues regardless of where they run.

Cross-Namespace Considerations

  • Secrets: Each namespace gets its own K8s Secret. Use External Secrets Operator or a shared values file to keep credentials in sync.
  • Service Account: Worker-only releases still need a ServiceAccount with IRSA annotations for S3 access.
  • KEDA: ScaledObjects are namespace-scoped. Each release creates its own KEDA resources; the cluster-wide KEDA operator discovers them automatically.
  • Network Policies: Ensure worker namespaces can reach PostgreSQL, Redis, external APIs, and storage endpoints.

Autoscaling

Best for scaling based on actual queue depth. Supports scale-to-zero.KEDA polls PostgreSQL to count queued/running tasks and adjusts replicas to maintain a target ratio.
Individual pools can override the global KEDA query and target:

Run Archiving

After each workflow run completes, the worker archives run data (state, progress, node IO, logs, content streams) from Redis to object storage (S3/GCS/Azure Blob). This ensures long-term persistence but adds per-run overhead from token acquisition and upload latency.

Archive Mode (ARCHIVE_MODE)

Configuration

Async Mode

In async mode, a periodic Celery task (batch_archive_runs) runs every ARCHIVE_BATCH_INTERVAL seconds and archives all completed runs that have been idle in Redis for at least that duration. This eliminates per-run cloud storage token acquisition and reduces GCP/AWS auth pressure under high concurrency.

Disabled Mode

Use disabled for pure performance benchmarking. Run data remains in Redis (subject to TTL) and can still be retrieved by the backend. The existing archive_orphaned_data periodic task (runs every 30 minutes) acts as a safety net and will eventually archive idle data regardless of mode.
In disabled mode, run data that exceeds its Redis TTL (4 hours for node IO, 60 days for state/progress) will be lost if not archived by the orphan cleanup task. Do not use this mode in production.

Verification

After deploying, verify the setup:

Environment

Platform environment variables and configuration layers

Secrets

Secret management, per-pool injection, and rotation

Scaling

General scaling strategies and capacity planning

Kubernetes

Kubernetes deployment guide