A transaction sets its own tenant context, so any connection serves any tenant

Table of Contents

1. Summary

A connection carries no tenant between transactions. Each transaction begins by setting its tenant, its party, its visible parties and its actor with set_config(..., true), which holds for the transaction only, and the settings travel in the same round trip as its first statement. When the transaction ends the settings end with it. Any connection therefore serves any tenant, the pool needs no partition by tenant, and a pooler in transaction mode can share connections.

2. Detail

2.1. What a transaction sets

Setting What it holds
app.current_tenant_id The tenant the transaction acts in
app.current_party_id The party the transaction acts as
app.visible_party_ids The parties whose rows the transaction may see
app.current_actor The account the audit columns name
app.current_service The service acting, for audit and for the policies of service roles

The time zone is not a setting of the connection. It is a default of each service's database role, ALTER ROLE ... SET TimeZone = 'UTC', so every server connection the role opens starts in UTC, whichever client the pooler hands it to. A connection carries nothing between transactions.

2.2. Row-level security reads them

The policies of PostgreSQL Row-Level Security read these settings. A statement outside a transaction that set them sees no tenant and no rows, so a forgotten context fails closed.

2.3. One round trip

The unit of work (A repository works inside an open transaction and never holds credentials) sends the settings and the first statement as one pipeline, so setting the context costs no round trip of its own.

3. See also

Emacs 29.3 (Org mode 9.6.15)