Skip to content

feat(server): pin a session to one worker with duckgres.session_affinity - #1044

Draft
posthog[bot] wants to merge 1 commit into
mainfrom
posthog-self-driving/featduckgres-pin-a-session-to-one-8efaa7
Draft

feat(server): pin a session to one worker with duckgres.session_affinity#1044
posthog[bot] wants to merge 1 commit into
mainfrom
posthog-self-driving/featduckgres-pin-a-session-to-one-8efaa7

Conversation

@posthog

@posthog posthog Bot commented Aug 9, 2026

Copy link
Copy Markdown

Problem

  • A serverless session can move between workers mid-session, and worker-side state that the exploratory tier does not replay is silently dropped — blocking a customer's migration off a deprecated dedicated warehouse.
  • escalateWorker (server/conn_tier.go) destroys the current session and creates a new one on another worker. Only catalog init (controlplane/control.go) and persistent user secrets (controlplane/session_mgr.go) replay onto it.
  • An ad-hoc ATTACH ... (TYPE postgres) catalog and an exported transaction snapshot do not replay, so statements that land on a different worker fail with Catalog db does not exist and SET TRANSACTION SNAPSHOT does not exist.
  • The only known workaround (pg_pool_max_connections=1) trades those errors for out-of-memory failures, so there is no safe workaround.

Change

  • Mechanism: a new opt-in startup GUC -c duckgres.session_affinity=true takes the connection off the exploratory tier, so it acquires its standard worker eagerly and keeps it for the whole session — no destroy-and-recreate, no migration.
  • useExploratoryTier gains a sessionAffinity exclusion, alongside the existing passthrough and duckgres.worker_* exclusions.
  • control.go parses and validates the option before a worker is spawned; a non-boolean value is rejected FATAL 22023, like the other duckgres.* startup options.
  • No new gate. Affinity needs no size GUC and no AllowClientWorkerProfile: it only reproduces the pre-tier default of one standard worker per connection.

Note on the second reported symptom

ATTACH, DETACH, SET TRANSACTION SNAPSHOT, and BEGIN ... ISOLATION LEVEL already classify as tierPinning today (parse-failure or default → pin), verified empirically against tier_classify.go. So the complementary "treat ATTACH as pinning" idea is already in place for a single connection; the remaining gap this PR closes is a whole-session opt-out for sessions whose state must never migrate.

Tests

  • TestParseSessionAffinityOption — boolean parsing and rejection of non-boolean values.
  • TestUseExploratoryTierExclusions — a session-affinity request bypasses the tier.
  • go build ./..., go vet, and the affected package tests pass. (TestCheckSocketDirWritable fails on a clean checkout too — unrelated, it asserts a permission the root test user always has.)

Why

The customer's migration is blocked and the dedicated instance they are on is being deprecated, so the failure is on a deadline. The errors are structural — one unguarded code path, not load — so they recur on every attempt.


Created with PostHog Desktop from this inbox report.

A `-c duckgres.session_affinity=true` startup option keeps a connection off the
exploratory small-worker tier, so the control plane acquires the standard worker
eagerly and never destroys and re-creates the session on another worker.

The exploratory tier only replays catalog init and persistent user secrets onto
a new worker. An ad-hoc `ATTACH ... (TYPE postgres)` catalog and an exported
transaction snapshot are not replayed, so a mid-session migration surfaced
"Catalog db does not exist" and "SET TRANSACTION SNAPSHOT does not exist". The
opt-in removes the migration for sessions that need this state.

The option needs no size GUC and no AllowClientWorkerProfile gate: it only
reproduces the pre-tier default of one standard worker per connection.

Generated-By: PostHog Code
Task-Id: 051216d4-3aea-4ad9-95f0-28d40ee2d43d
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

Test Impact Plan

Deterministic summary of how this PR changes tests, CI runners, and coverage-risk signals.

Summary

Area Added Changed Deleted
Test files 1 1 0
E2E/journey files 0 0 0
Workflow files 0 0 0

Signals

  • Test cases: +1 / -0
  • Assertions: +7 / -0
  • Skips or known failures added: 0
  • Workflow continue-on-error added: 0
  • Workflow path filters added: 0
  • Test commands removed from justfile: 0
  • E2E/journey retry lines added: 0

Coverage risk: neutral or increased

No coverage-reduction warnings detected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants