Process lifecycle
Skill matejformanek/postgres-claude/.claude/skills/process-lifecycle
PostgreSQL's per-connection multi-process model — postmaster fork, backend startup / initialization / query loop / clean shutdown, auxiliary processes (checkpointer, bgwriter, walwriter, autovacuum launcher, WAL summarizer, pgarch), background workers (bgworker.c registry + parallel/logical-rep workers), signal handling, and the FATAL/ERROR/PANIC hierarchy. Loads when the user asks about how a connection becomes a backend, what runs before the first query, why a query dies mid-flight, how signals + ProcessInterrupts + CHECK_FOR_INTERRUPTS work together, how autovacuum / bgworker workers get scheduled, or when planning a feature that hooks a startup phase / adds a new auxiliary process / touches shutdown ordering. Skip when the question is about client-side (libpq, drivers) or about the SQL-level session properties (that's `tcop` for query dispatch, `gucs-config` for GUCs).From its SKILL.md
npx -y skills add matejformanek/postgres-claude --skill process-lifecycleAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
11.1 KB, ~2.5k tokens by cl100k_base, as published. Nobody here has run it
process-lifecycle — postmaster, backends, aux processes, bgworkers
PostgreSQL uses a per-connection process model, not threads. Every client connection gets its own OS process, forked from the postmaster. New backends do NOT inherit query state — every connection starts fresh through InitPostgres. This model shapes almost every feature.
The five process classes
| Class | Files | Lifetime | Example |
|---|---|---|---|
| Postmaster | postmaster/postmaster.c, pmchild.c, launch_backend.c, fork_process.c | Cluster-lifetime | The parent process — accepts connections, forks children, reaps exits, restarts on crash. |
| Regular backend | tcop/postgres.c, tcop/backend_startup.c | Connection-lifetime | The child that runs SQL for one client. |
| Auxiliary process | postmaster/auxprocess.c + one file each: checkpointer.c, bgwriter.c, walwriter.c, walsummarizer.c, startup.c, pgarch.c, syslogger.c, interrupt.c | Cluster-lifetime | Always-on infrastructure processes; not for user queries. |
| Bgworker | postmaster/bgworker.c + registered by extensions | Configurable (per session / for lifetime of cluster / restart on crash) | Autovacuum workers, parallel query workers, logical-rep apply workers, extension workers. |
| Autovacuum launcher/worker | postmaster/autovacuum.c | Cluster-lifetime launcher + short-lived workers | Special case: launcher is aux, workers are bgworkers. |
Backend lifecycle (regular query-serving backend)
Every incoming connection follows this sequence:
- Postmaster accepts —
postmaster.cServerLoopsees a new socket, callsBackendStartupinlaunch_backend.c. - Fork or exec-and-fork — On Unix,
fork()copies the postmaster into a child. On Windows orEXEC_BACKENDbuilds, the child re-execs and re-attaches to shmem viaSubPostmasterMain. - Auth handshake —
backend_startup.cruns the startup message exchange, TLS/GSS, SCRAM/MD5/etc. authentication. Fails here → child exits before any query state exists. InitPostgres— This is the big one (inutils/init/postinit.c). Loads GUC per-role/per-db settings, opens the database's relcache/syscache, checks CONNECT permission, runs the login_PG_inithooks, ends up inPostgresMain.PostgresMainloop — the SQL query loop (intcop/postgres.c). ReadCommand → exec → send RowDescription/DataRow/CommandComplete → ReadyForQuery → next iteration.- Shutdown — Client sends X (Terminate), or postmaster signals shutdown, or fatal error.
proc_exitruns registered callbacks (seeon_shmem_exit/on_proc_exitinstorage/ipc/ipc.c), releases locks + LWLocks, detaches from shmem.
The interrupt / signal system
Because backends can be interrupted between statements (query cancel, admin shutdown, sighup, deadlock), there's a specific pattern:
- Signal handlers must be async-signal-safe. They set flags (
InterruptPending,QueryCancelPending,ProcDiePending,ConfigReloadPending) and set the process latch (SetLatch(MyLatch)). CHECK_FOR_INTERRUPTS()— macros sprinkled through the code that check the flags at safe points and callProcessInterrupts(intcop/postgres.c) if any are set.ProcessInterrupts— the actual interrupt handler. Runs at safe points, may callereport(FATAL/ERROR)to unwind orLATCH_WAIT_TIMEOUThandling.- Safe interruption points — the code base has thousands. Long-running loops need to include
CHECK_FOR_INTERRUPTS()— a missing one → uncancelable query.
Common signals + their flags:
SIGINT(query cancel) →QueryCancelPending.SIGTERM(shutdown) →ProcDiePending.SIGHUP(reload conf) →ConfigReloadPending.SIGUSR1(procsignal — multiplexed) → reason-specific flags viaprocsignal.c.
Auxiliary processes at a glance
Each aux process has its own file with a Main function that the postmaster spawns via SubPostmasterMain (Windows / EXEC_BACKEND) or forks directly:
| File | Function | Purpose |
|---|---|---|
startup.c | StartupProcessMain | Runs crash recovery / WAL replay at startup. Exits once redo completes. |
checkpointer.c | CheckpointerMain | Runs periodic checkpoints; writes the shutdown stats file. |
bgwriter.c | BackgroundWriterMain | Writes dirty buffers to smooth checkpoint I/O. |
walwriter.c | WalWriterMain | Flushes WAL buffers asynchronously. |
walsummarizer.c | WalSummarizerMain | (PG 17+) Summarizes WAL for incremental backup. |
pgarch.c | PgArchiverMain | Archives completed WAL segments (archive_command / archive_library). |
syslogger.c | SysLoggerMain | Rotates + captures postmaster/backend stderr when logging_collector=on. |
interrupt.c | Shared aux-process signal helpers | Not a process itself — the signal handlers shared across aux processes. |
Bgworker registration
Extensions and core code both use RegisterBackgroundWorker (in postmaster/bgworker.c):
- Static — called from
_PG_initat postmaster start. Fixed slot count (max_worker_processesGUC). - Dynamic —
RegisterDynamicBackgroundWorkerat runtime; used by parallel query (from a backend) and by extensions.
Bgworkers have flags controlling: shared-memory access, database connection, restart-on-crash policy, restart interval. See knowledge/idioms/background-worker-startup.md for the flag matrix and lifecycle diagram.
Common patch shapes
Add a startup-lifecycle hook
The scenario add-startup-hook (see knowledge/scenarios/add-startup-hook.md) covers this end-to-end. Short version:
- Hook typically lives in
PostmasterMain(postmaster-wide) orInitPostgres(per-backend). - Decide: cluster-once vs backend-per-connection.
- Existing patterns:
shared_preload_libraries(postmaster startup),local_preload_libraries+session_preload_libraries(per-backend),ClientAuthentication_hook(auth-time),emit_log_hook(per log record).
Add a new auxiliary process
Rare. Requires:
- New file under
src/backend/postmaster/<name>.cwith a<Name>Mainfunction. - Registration in
postmaster/postmaster.c(grep forStartChildProcess/StartAuxiliaryProcess). - Signal handlers (usually delegated to
interrupt.chelpers). - Shmem region if it exchanges data with backends (via
ShmemInit). - Consider whether it should restart on crash (postmaster's
HandleChildCrash).
Note: for most "run something periodically" use cases, a bgworker is preferable — less core code to touch, extensions can add without a core patch.
Add a signal / interrupt reason
- New
PROCSIGNAL_*constant insrc/include/storage/procsignal.h. - Signal-dispatcher
procsignal_sigusr1_handlercase instorage/ipc/procsignal.c. - Flag +
ProcessInterruptscase intcop/postgres.c. - Setter helper if the reason is per-target-backend (e.g.
procsignal_ProcSendSignal(pid, PROCSIG_...))`. - Docs for what "kills" or "cancels" this new interrupt cause.
Pitfalls
- Fork copies memory but not open file descriptors semantically — a
pallocbefore fork is fine (COW), but adsm_attachbefore fork is not (the child would double-detach). This is why aux processes and bgworkers do shmem init in their own Main, not inherited state. - Signal handlers cannot log via ereport — that's
elog(LOG, ...)calls internally allocating inErrorContext, which is not async-signal-safe. Set a flag, return, let the main loop pick it up viaCHECK_FOR_INTERRUPTS. InitPostgresreads pg_authid + pg_database + role/db GUC settings BEFORE the user has issued any SQL — extensions in_PG_initneed to be careful about assuming database context is complete.shared_preload_librariesvssession_preload_librariesvslocal_preload_libraries— different postmaster/backend load points; different capabilities (shmem allocation is only possible fromshared_preload_libraries).- Bgworker signal setup — a bgworker inherits SIG_IGN/SIG_DFL from postmaster. It MUST reset signal handlers in its Main via
pqsignalcalls before doing any interruptible work. proc_exitvs_exitvsabort—proc_exit(0)runs registered callbacks (releases locks, detaches shmem, closes files);_exitskips them;abort(PANIC) triggers a cluster-wide restart. Never call_exitin a place that's holding a lock.EXEC_BACKENDbuilds are Windows-native but also used for testing on Unix — a patch that "works" on your Linux dev box may still fail EXEC_BACKEND CI because the fork-then-exec path is different. Test with-DEXEC_BACKENDlocally when touching startup code.
Related corpus
- Subsystems:
tcop(the query loop side),main(backend entry),libpq-backend(auth handshake),access-transam(WAL / xact IDs, needed at startup). - Idioms:
background-worker-startup,apply-worker-loop,process-utility-hook-chain,abort-transaction-cleanup,crash-recovery-startup. - Data structures:
pgproc-fields(the per-backend PGPROC slot in shmem). - Scenarios:
add-startup-hook,add-new-bgworker. - File docs: 20 files under
knowledge/files/src/backend/postmaster/+src/backend/tcop/.
Corpus-chain shortcut
python3 scripts/corpus-chain.py --scenario add-startup-hook
python3 scripts/corpus-chain.py --file src/backend/tcop/postgres.c
python3 scripts/corpus-chain.py --file src/backend/postmaster/postmaster.c
Third command in particular surfaces the full 20-file neighborhood of the postmaster tree.
Boundary
Use this skill for backend/aux/bgworker/postmaster lifecycle questions.
Don't use for:
- libpq / client-side driver — that's
src/interfaces/libpq/; different codebase, different lifecycle. - Individual SQL commands' handling — that's
tcop(dispatch) +commands/(per-statement). - GUC config loading — use
gucs-configskill; touches lifecycle but focused on the config side. - Extension
_PG_initdetails — usebgworker-and-extensions; this skill covers the invocation timing, not the extension-authoring surface.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.