Tenant context support for background job processing.
This namespace provides utilities for executing background jobs within tenant-specific database schema contexts. It integrates with the multi-tenant architecture by extracting tenant-id from job metadata and setting the appropriate PostgreSQL search_path before job execution.
Key Features:
Usage: (require '[boundary.jobs.shell.tenant-context :as tenant-jobs])
;; Enqueue job with tenant context (tenant-jobs/enqueue-tenant-job! job-queue tenant-id :send-email {:to "user@example.com"})
;; Process job with tenant context (tenant-jobs/process-tenant-job! job handler-fn db-ctx tenant-service)
See ADR-004 for architecture details (lines 525-554).
Tenant context support for background job processing.
This namespace provides utilities for executing background jobs within
tenant-specific database schema contexts. It integrates with the multi-tenant
architecture by extracting tenant-id from job metadata and setting the
appropriate PostgreSQL search_path before job execution.
Key Features:
- Extract tenant-id from job metadata
- Set database search_path to tenant schema
- Execute job handlers in tenant context
- Automatic fallback to public schema if no tenant
Usage:
(require '[boundary.jobs.shell.tenant-context :as tenant-jobs])
;; Enqueue job with tenant context
(tenant-jobs/enqueue-tenant-job! job-queue tenant-id :send-email
{:to "user@example.com"})
;; Process job with tenant context
(tenant-jobs/process-tenant-job! job handler-fn db-ctx tenant-service)
See ADR-004 for architecture details (lines 525-554).(enqueue-tenant-job! job-queue tenant-id job-type args)(enqueue-tenant-job! job-queue
tenant-id
job-type
args
{:keys [priority max-retries queue-name]
:or {priority :normal max-retries 3 queue-name :default}})Enqueue a background job with tenant context.
This stores the tenant-id in job metadata so the worker can execute the job in the correct tenant schema context.
Args: job-queue: IJobQueue implementation tenant-id: Tenant UUID job-type: Job type keyword (e.g., :send-email, :process-upload) args: Job arguments map options: Optional map with: :priority - :critical, :high, :normal (default), :low :max-retries - Retry count (default: 3) :queue-name - Queue name (default: :default)
Returns: Job UUID
Example: (enqueue-tenant-job! job-queue tenant-uuid :send-email {:to "user@example.com" :subject "Welcome!" :body "Thanks for signing up."} {:priority :high})
Notes:
Enqueue a background job with tenant context.
This stores the tenant-id in job metadata so the worker can execute
the job in the correct tenant schema context.
Args:
job-queue: IJobQueue implementation
tenant-id: Tenant UUID
job-type: Job type keyword (e.g., :send-email, :process-upload)
args: Job arguments map
options: Optional map with:
:priority - :critical, :high, :normal (default), :low
:max-retries - Retry count (default: 3)
:queue-name - Queue name (default: :default)
Returns:
Job UUID
Example:
(enqueue-tenant-job! job-queue
tenant-uuid
:send-email
{:to "user@example.com"
:subject "Welcome!"
:body "Thanks for signing up."}
{:priority :high})
Notes:
- Tenant-id is stored in job :metadata
- Jobs without tenant-id run in public schema
- Worker must have access to db-context and tenant-service(extract-tenant-context job tenant-service)Extract tenant context from job metadata.
Args: job: Job map with :metadata tenant-service: ITenantService implementation
Returns: Map with: :tenant-id - Tenant UUID (or nil if not found) :tenant-schema - Tenant schema name (or nil) :tenant-entity - Full tenant entity (or nil)
Notes:
Extract tenant context from job metadata.
Args:
job: Job map with :metadata
tenant-service: ITenantService implementation
Returns:
Map with:
:tenant-id - Tenant UUID (or nil if not found)
:tenant-schema - Tenant schema name (or nil)
:tenant-entity - Full tenant entity (or nil)
Notes:
- Returns nil values if job has no tenant-id
- Logs warning if tenant-id present but tenant not found
- Jobs without tenant run in public schema (multi-tenant optional)(process-tenant-job! job
handler-fn
db-ctx
tenant-service
tenant-schema-provider)Process a job with tenant schema context.
This wraps job handler execution to:
Args: job: Job map with :id, :job-type, :args, :metadata handler-fn: Job handler function (fn [args db-ctx] -> result) db-ctx: Database context with :datasource, :database-type tenant-service: ITenantService implementation tenant-schema-provider: ITenantSchemaProvider implementation (optional, required for tenant jobs)
Returns: Result map with :success?, :result or :error
Example: (process-tenant-job! job (fn [args db-ctx] ;; Handler logic here {:success? true :result {:rows 5}}) db-ctx tenant-service tenant-schema-provider)
Notes:
Security:
Process a job with tenant schema context.
This wraps job handler execution to:
1. Extract tenant-id from job metadata
2. Lookup tenant entity to get schema name
3. Set PostgreSQL search_path to tenant schema
4. Execute job handler with database connection
5. Restore search_path after execution
Args:
job: Job map with :id, :job-type, :args, :metadata
handler-fn: Job handler function (fn [args db-ctx] -> result)
db-ctx: Database context with :datasource, :database-type
tenant-service: ITenantService implementation
tenant-schema-provider: ITenantSchemaProvider implementation (optional, required for tenant jobs)
Returns:
Result map with :success?, :result or :error
Example:
(process-tenant-job! job
(fn [args db-ctx]
;; Handler logic here
{:success? true :result {:rows 5}})
db-ctx
tenant-service
tenant-schema-provider)
Notes:
- Handler receives db-ctx as second argument
- Handler should use db-ctx for database operations
- search_path is automatically managed
- Falls back to public schema if no tenant
- Only works with PostgreSQL (other databases use public schema)
Security:
- Tenant isolation enforced via search_path
- Each job execution gets isolated transaction
- Schema validation before execution
- Automatic cleanup on error(wrap-handler-with-tenant-context handler-fn
db-ctx
tenant-service
tenant-schema-provider)Wrap an existing job handler to add tenant context support.
This is a convenience function for integrating tenant context into existing job handlers without modifying them.
Args: handler-fn: Original handler (fn [args] -> result) db-ctx: Database context tenant-service: ITenantService implementation tenant-schema-provider: ITenantSchemaProvider implementation (optional, required for tenant jobs)
Returns: Wrapped handler (fn [job] -> result)
Example: (def my-handler (wrap-handler-with-tenant-context (fn [args db-ctx] ;; Original handler logic {:success? true :result {}}) db-ctx tenant-service tenant-schema-provider))
;; Register wrapped handler (ports/register-handler! registry :send-email my-handler)
Notes:
Wrap an existing job handler to add tenant context support.
This is a convenience function for integrating tenant context into
existing job handlers without modifying them.
Args:
handler-fn: Original handler (fn [args] -> result)
db-ctx: Database context
tenant-service: ITenantService implementation
tenant-schema-provider: ITenantSchemaProvider implementation (optional, required for tenant jobs)
Returns:
Wrapped handler (fn [job] -> result)
Example:
(def my-handler
(wrap-handler-with-tenant-context
(fn [args db-ctx]
;; Original handler logic
{:success? true :result {}})
db-ctx
tenant-service
tenant-schema-provider))
;; Register wrapped handler
(ports/register-handler! registry :send-email my-handler)
Notes:
- Wrapped handler expects job (not just args)
- Tenant context extracted and applied automatically
- Original handler must accept db-ctx as second argcljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |