feat(db): attribute Postgres connections by runtime via application_name (#5211)

* feat(db): attribute Postgres connections by runtime via application_name

* improvement(db): label migration-runner connection sim-migrate; trim DB_APP_NAME comment

* fix(db): label realtime's shared @sim/db connections sim-realtime too

The realtime process uses both its own socketDb pool and the shared @sim/db
client (handlers, preflight, permissions). Only socketDb was labeled, so the
shared client defaulted to sim-app, mislabeling much of realtime's DB traffic.
Set DB_APP_NAME=sim-realtime at the process level (bootstrap before the dynamic
@/index import for prod; dev/start scripts for local) so both clients report it.
This commit is contained in:
Theodore Li
2026-06-25 17:11:23 -04:00
committed by GitHub
parent 9e1a4ac5d1
commit a68d38ae75
7 changed files with 24 additions and 4 deletions
+2 -2
View File
@@ -9,8 +9,8 @@
"node": ">=20.0.0"
},
"scripts": {
"dev": "bun --watch src/index.ts",
"start": "bun src/index.ts",
"dev": "DB_APP_NAME=sim-realtime bun --watch src/index.ts",
"start": "DB_APP_NAME=sim-realtime bun src/index.ts",
"type-check": "tsc --noEmit",
"lint": "biome check --write --unsafe .",
"lint:check": "biome check .",
+7
View File
@@ -6,4 +6,11 @@
import { loadRuntimeSecrets } from '@sim/runtime-secrets'
await loadRuntimeSecrets()
/**
* Label every Postgres connection this process opens as `sim-realtime` — both
* the realtime `socketDb` pool and the shared `@sim/db` client used by handlers,
* preflight, and permissions. Set before importing `@/index` so it lands before
* `@sim/db` reads it at module-eval time. `??=` respects an explicit override.
*/
process.env.DB_APP_NAME ??= 'sim-realtime'
await import('@/index')
+1
View File
@@ -40,6 +40,7 @@ const socketDb = drizzle(
connect_timeout: 20,
max: 15,
onnotice: () => {},
connection: { application_name: process.env.DB_APP_NAME ?? 'sim-realtime' },
}),
'socketDb'
),
+1
View File
@@ -20,6 +20,7 @@ export const env = createEnv({
// Core Database & Authentication
DATABASE_URL: z.string().url(), // Primary database connection string
DATABASE_REPLICA_URL: z.string().url().optional(), // Read-replica connection string; opt-in reads fall back to the primary when unset
DB_APP_NAME: z.string().optional(), // Postgres application_name for query attribution (sim-app/sim-trigger/sim-realtime)
BETTER_AUTH_URL: z.string().url(), // Base URL for Better Auth service
BETTER_AUTH_SECRET: z.string().min(32), // Secret key for Better Auth JWT signing
DISABLE_REGISTRATION: z.boolean().optional(), // Flag to disable new user registration
+6 -1
View File
@@ -2,7 +2,11 @@ import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http'
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { resourceFromAttributes } from '@opentelemetry/resources'
import { additionalFiles, additionalPackages } from '@trigger.dev/build/extensions/core'
import {
additionalFiles,
additionalPackages,
syncEnvVars,
} from '@trigger.dev/build/extensions/core'
import { defineConfig } from '@trigger.dev/sdk'
import { env } from './lib/core/config/env'
import { parseOtlpHeaders } from './lib/monitoring/otlp'
@@ -58,6 +62,7 @@ export default defineConfig({
build: {
external: ['isolated-vm', '@earendil-works/pi-coding-agent', 'cpu-features'],
extensions: [
syncEnvVars(() => [{ name: 'DB_APP_NAME', value: 'sim-trigger' }]),
additionalFiles({
files: [
'./lib/execution/isolated-vm-worker.cjs',
+1
View File
@@ -13,6 +13,7 @@ const poolOptions = {
idle_timeout: 20,
connect_timeout: 30,
onnotice: () => {},
connection: { application_name: process.env.DB_APP_NAME ?? 'sim-app' },
}
const postgresClient = instrumentPoolClient(
+6 -1
View File
@@ -45,7 +45,12 @@ const hasDirectMigrationUrl = Boolean(process.env.MIGRATION_DATABASE_URL)
* default recycles the connection after 30–60 min, silently dropping the
* session advisory lock and `SET`s.
*/
const client = postgres(url, { max: 1, connect_timeout: 10, max_lifetime: null })
const client = postgres(url, {
max: 1,
connect_timeout: 10,
max_lifetime: null,
connection: { application_name: 'sim-migrate' },
})
/**
* Cross-process migration lock. drizzle's `migrate()` has no built-in lock, so