---
title: "Run every background job inside its tenant · Agent Wranglers"
url: https://agentwranglers.se/playbook/data/multi-tenancy/tenant-context-in-jobs
id: DAT-68
level: Required
risk: data
updated: 2026-10-22
tokens: 1047
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Run every background job inside its tenant

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Multi-tenancy](https://agentwranglers.se/playbook/data/multi-tenancy.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-22.

- ID: DAT-68
- Level: Required
- Chapter: [Multi-tenancy](https://agentwranglers.se/playbook/data/multi-tenancy.md)
- Rule: Put the tenant ID in every job's payload, and make the worker set the tenant context before it touches data. A job without a tenant ID fails at once.
- Check: A unit test sends each job type with no tenant ID, and each fails before any query runs. A test enqueues a job for tenant A that reads a table, and the job sees 0 rows of tenant B. A code search finds no job handler registered outside the tenant wrapper.
- Risk: Data leaked or lost
- How: Requests get the tenant from the session or the address, as [Keep the organisation in the address](https://agentwranglers.se/playbook/accounts/organisations-and-teams/organisation-in-url.md) shows. Jobs, scheduled tasks and queue consumers have no request, so they must carry it. Wrap every handler in one function that reads the tenant ID, opens a transaction and sets the database setting with `SET LOCAL` or `set_config(..., true)`. Then row-level security applies in workers as it does in requests. A job that serves every tenant, such as a nightly report, loops over tenants and runs each one inside its own context. Never run it as a role that bypasses the policies. Make the job safe to repeat, as [Make every job safe to run twice](https://agentwranglers.se/playbook/scaling/background-jobs-and-queues/idempotent-jobs.md) says, with the tenant in its key.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
export const tenantJob = handler => async job => {
  const { tenantId } = job.data;
  if (!tenantId) throw new Error(`job ${job.name} has no tenantId`);
  return db.tx(async tx => {
    await tx.none("SELECT set_config('app.tenant_id', $1, true)", [String(tenantId)]);
    return handler(tx, job.data);
  });
};

worker.register('monthly-invoice', tenantJob(createMonthlyInvoice));
```

### Python example

```python
def tenant_job(handler):
    def run(payload: dict):
        tenant_id = payload.get("tenant_id")
        if not tenant_id:
            raise ValueError(f"job {handler.__name__} has no tenant_id")
        with conn.transaction():
            conn.execute("SELECT set_config('app.tenant_id', %s, true)", (str(tenant_id),))
            return handler(conn, payload)
    return run

queue.register("monthly-invoice", tenant_job(create_monthly_invoice))
```

## Sources

- [PostgreSQL row security policies](https://www.postgresql.org/docs/current/ddl-rowsecurity.html)
- [PostgreSQL configuration settings functions](https://www.postgresql.org/docs/current/functions-admin.html)

## Related rules

- ACC-47 [Keep the organisation in the address](https://agentwranglers.se/playbook/accounts/organisations-and-teams/organisation-in-url.md) in Accounts and identity
- SCL-17 [Make every job safe to run twice](https://agentwranglers.se/playbook/scaling/background-jobs-and-queues/idempotent-jobs.md) in Scaling

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/data/multi-tenancy/tenant-context-in-jobs">Agent Wranglers data and databases playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Choose the isolation model before the first customer](https://agentwranglers.se/playbook/data/multi-tenancy/tenant-isolation-model.md)
- Next: [Keep files and search indexes apart by tenant](https://agentwranglers.se/playbook/data/multi-tenancy/tenant-scoped-storage.md)
- [Multi-tenancy](https://agentwranglers.se/playbook/data/multi-tenancy.md)
