Skip to content

Multi-Tenancy

The multi-tenancy extension enables tenant-isolated job processing for SaaS deployments. It defines how tenants are identified, how resources are isolated, and how fairness is maintained across tenants.

Tenants are identified via metadata or HTTP headers:

{
"type": "report.generate",
"args": ["q1-2026"],
"meta": {
"tenant_id": "tenant_acme"
}
}

Or via request header:

Terminal window
POST /ojs/v1/jobs
X-OJS-Tenant: tenant_acme

The backend extracts the tenant ID and associates it with the job for the remainder of its lifecycle.

Separate queues and workers per tenant:

tenant_acme.default → workers for acme
tenant_beta.default → workers for beta

Strongest isolation. No shared resources. Higher operational overhead.

All tenants share queues. Jobs are tagged with tenant_id and fairness is enforced at dispatch time:

default queue → [job(acme), job(beta), job(acme), job(acme)]
↓ fair dispatch
worker processes: acme, beta, acme, acme (interleaved)

Simplest to operate. Fairness depends on scheduling strategy.

Per-tenant sub-queues within a shared infrastructure. Workers consume from all sub-queues using round-robin:

default.tenant_acme → shared worker pool (round-robin)
default.tenant_beta →

Combines isolation benefits with operational simplicity.

ResourceDescription
concurrencyMax simultaneous active jobs per tenant
enqueue_rateMax jobs per second per tenant
queue_depthMax queued jobs per tenant
scheduled_jobsMax scheduled jobs per tenant
{
"tenant_id": "tenant_acme",
"limits": {
"concurrency": 50,
"enqueue_rate": 100,
"queue_depth": 10000,
"scheduled_jobs": 1000
}
}

When a limit is exceeded, the backend returns 429 with tenant-specific rate limit information.

Backends SHOULD detect and mitigate noisy neighbors—tenants that consume disproportionate resources:

  1. Detection: Monitor per-tenant throughput, error rates, and resource consumption.
  2. Throttling: Automatically reduce a noisy tenant’s effective rate limit.
  3. Alerting: Emit events when a tenant approaches or exceeds limits.
  • Rate limiting: Rate limits can be scoped by tenant using composite keys.
  • Dead letter: DLQ queries MUST be filterable by tenant_id.
  • Backpressure: Queue depth thresholds can be set per tenant.
  • Observability: Metrics SHOULD include a tenant_id dimension.
  • Authorization: Tenant scoping MUST be enforced at the authorization layer.