Skip to content

PATTERN Cited by 1 source

Dedicated application_name per workload

Pattern: use distinct Postgres application_name connection- string parameters per logical workload (web tier / background jobs / one-off scripts / migrations / analytics), so that resource budgets can isolate workloads at the connection layer without requiring application-level SQLCommenter discipline. The application_name value is set by the Postgres driver, visible in pg_stat_activity, and available to Traffic Control as a budget-matching axis on every query — regardless of whether the application itself emits any tags.

Shape (Go)

One helper per workload class; each configures a dedicated *sql.DB pool with a distinct application_name. Canonical shape (Source: sources/2026-04-21-planetscale-patterns-for-postgres-traffic-control):

Background-job pool — fixed application_name, low connection cap:

func newJobDB(dsn string) (*sql.DB, error) {
    jobDSN, err := url.Parse(dsn)
    if err != nil { return nil, err }
    q := jobDSN.Query()
    q.Set("application_name", "background-jobs")
    jobDSN.RawQuery = q.Encode()
    db, err := sql.Open("pgx", jobDSN.String())
    if err != nil { return nil, err }
    db.SetMaxOpenConns(4)  // jobs don't need high concurrency
    return db, nil
}

Script pool — script-name-interpolated application_name:

func scriptDB(dsn, scriptName string) (*sql.DB, error) {
    u, _ := url.Parse(dsn)
    q := u.Query()
    q.Set("application_name", "script-"+scriptName)
    u.RawQuery = q.Encode()
    return sql.Open("pgx", u.String())
}

Call sites: scriptDB(dsn, "backfill-order-totals") produces application_name=script-backfill-order-totals; each one-off script carries a distinct, human-readable identifier.

Why application_name, not SQLCommenter

application_name is a Postgres-native connection parameter with three properties no application-level tag has:

  1. Set at connection time, not per query. One setting covers every query on the connection.
  2. Impossible to forget. No middleware to install, no ORM wrapper to register, no per-call-site discipline.
  3. Visible in pg_stat_activity. Operators diagnosing the database from psql see the workload tag before any app-side tooling engages.

For workloads where the execution environment itself is the classification (this is the job runner vs this is a one-off script), a driver-level tag is the right altitude. For per-request tags (route, tier, feature), SQLCommenter is the right altitude. Both compose — a query from the web tier carries application_name='web' plus SQLCommenter route, tier, etc.

Canonical workload classes

The Brown post names three concrete classes; the pattern extends to any distinct lifecycle:

Workload application_name
Web tier (request-scoped, high concurrency) web or per-service (pscale_api)
Background jobs (worker pool, bounded concurrency) background-jobs
One-off scripts script-<script-name>
Schema migrations migration-<version>
Analytics / exports analytics

Each class gets a distinct *sql.DB pool with its own SetMaxOpenConns and its own Traffic Control budget.

Double-layered isolation

The pattern composes connection-pool caps with Traffic Control budgets for defence in depth:

  • SetMaxOpenConns(4) is an application-layer cap — the driver refuses to open more than 4 simultaneous connections. Enforced before a query even reaches the database.
  • Traffic Control budget on application_name='background- jobs' is a database-layer cap — the extension blocks or notices over-budget queries at the wire protocol.

The two caps don't redundantly duplicate each other. Connection count ≠ CPU share ≠ worker concurrency; each lever addresses a different resource dimension.

Canonical framing

Verbatim (Source: sources/2026-04-21-planetscale-patterns-for-postgres-traffic-control):

"Setting application_name on the connection string level in code ensures that it is always set for this service, no matter the query or connection string given. You can pair this with SQL comments as described above for even more fine- grained control and insights into your queries."

The "no matter the query" clause is the load-bearing property: every query on every connection in the pool inherits the workload tag without per-call-site cooperation.

Operational notes

  • Env-var PGAPPNAME is a third way to set the tag, useful when the connection string is not in the application's control (e.g. psql / pg_dump invocations).
  • Connection pooling with pgbouncer session mode preserves application_name; transaction mode may rebind per transaction — check pgbouncer configuration.
  • application_name character limit is 63 bytes in Postgres. Long script names get truncated; keep names compact.
  • Warn-mode rollout for background jobs is mandatory. "Create a Traffic Control budget for application_name= 'background-jobs' in Warn mode before you run this job next. Observe how much of the database's resources your background work typically consumes. Then switch to Enforce at a level where it can't crowd out interactive traffic even if a job goes sideways."
  • Dedicated database role per service (via Postgres username) is the stricter, orthogonal variant — a role can be revoked, role passwords rotated, per-role GRANTs applied. application_name is an unverified self-declared label; role-based identity is authenticated.

Seen in

Last updated · 378 distilled / 1,213 read