Skip to content

Commit a68d38a

Browse files
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.
1 parent 9e1a4ac commit a68d38a

7 files changed

Lines changed: 24 additions & 4 deletions

File tree

apps/realtime/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
"node": ">=20.0.0"
1010
},
1111
"scripts": {
12-
"dev": "bun --watch src/index.ts",
13-
"start": "bun src/index.ts",
12+
"dev": "DB_APP_NAME=sim-realtime bun --watch src/index.ts",
13+
"start": "DB_APP_NAME=sim-realtime bun src/index.ts",
1414
"type-check": "tsc --noEmit",
1515
"lint": "biome check --write --unsafe .",
1616
"lint:check": "biome check .",

apps/realtime/src/bootstrap.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,11 @@
66
import { loadRuntimeSecrets } from '@sim/runtime-secrets'
77

88
await loadRuntimeSecrets()
9+
/**
10+
* Label every Postgres connection this process opens as `sim-realtime` — both
11+
* the realtime `socketDb` pool and the shared `@sim/db` client used by handlers,
12+
* preflight, and permissions. Set before importing `@/index` so it lands before
13+
* `@sim/db` reads it at module-eval time. `??=` respects an explicit override.
14+
*/
15+
process.env.DB_APP_NAME ??= 'sim-realtime'
916
await import('@/index')

apps/realtime/src/database/operations.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const socketDb = drizzle(
4040
connect_timeout: 20,
4141
max: 15,
4242
onnotice: () => {},
43+
connection: { application_name: process.env.DB_APP_NAME ?? 'sim-realtime' },
4344
}),
4445
'socketDb'
4546
),

apps/sim/lib/core/config/env.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const env = createEnv({
2020
// Core Database & Authentication
2121
DATABASE_URL: z.string().url(), // Primary database connection string
2222
DATABASE_REPLICA_URL: z.string().url().optional(), // Read-replica connection string; opt-in reads fall back to the primary when unset
23+
DB_APP_NAME: z.string().optional(), // Postgres application_name for query attribution (sim-app/sim-trigger/sim-realtime)
2324
BETTER_AUTH_URL: z.string().url(), // Base URL for Better Auth service
2425
BETTER_AUTH_SECRET: z.string().min(32), // Secret key for Better Auth JWT signing
2526
DISABLE_REGISTRATION: z.boolean().optional(), // Flag to disable new user registration

apps/sim/trigger.config.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http'
22
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'
33
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
44
import { resourceFromAttributes } from '@opentelemetry/resources'
5-
import { additionalFiles, additionalPackages } from '@trigger.dev/build/extensions/core'
5+
import {
6+
additionalFiles,
7+
additionalPackages,
8+
syncEnvVars,
9+
} from '@trigger.dev/build/extensions/core'
610
import { defineConfig } from '@trigger.dev/sdk'
711
import { env } from './lib/core/config/env'
812
import { parseOtlpHeaders } from './lib/monitoring/otlp'
@@ -58,6 +62,7 @@ export default defineConfig({
5862
build: {
5963
external: ['isolated-vm', '@earendil-works/pi-coding-agent', 'cpu-features'],
6064
extensions: [
65+
syncEnvVars(() => [{ name: 'DB_APP_NAME', value: 'sim-trigger' }]),
6166
additionalFiles({
6267
files: [
6368
'./lib/execution/isolated-vm-worker.cjs',

packages/db/db.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const poolOptions = {
1313
idle_timeout: 20,
1414
connect_timeout: 30,
1515
onnotice: () => {},
16+
connection: { application_name: process.env.DB_APP_NAME ?? 'sim-app' },
1617
}
1718

1819
const postgresClient = instrumentPoolClient(

packages/db/scripts/migrate.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,12 @@ const hasDirectMigrationUrl = Boolean(process.env.MIGRATION_DATABASE_URL)
4545
* default recycles the connection after 30–60 min, silently dropping the
4646
* session advisory lock and `SET`s.
4747
*/
48-
const client = postgres(url, { max: 1, connect_timeout: 10, max_lifetime: null })
48+
const client = postgres(url, {
49+
max: 1,
50+
connect_timeout: 10,
51+
max_lifetime: null,
52+
connection: { application_name: 'sim-migrate' },
53+
})
4954

5055
/**
5156
* Cross-process migration lock. drizzle's `migrate()` has no built-in lock, so

0 commit comments

Comments
 (0)