Skip to content

SIGTERM handler calls exit(0) without running plugin fini hooks #1537

Description

@ewhauser

Summary

install_sigterm_handler() in pgdog/src/main.rs ends the process with exit(0) as soon as SIGTERM arrives. That path never calls plugin::shutdown(), so plugins loaded through [[plugins]] do not get their fini hook. The graceful path (shutdown()plugin::shutdown()) does run fini, so a plugin behaves differently depending on how PgDog was stopped.

SIGTERM is how Kubernetes (and most supervisors) stop a pod, so in practice fini is never invoked on a rollout. Any plugin that buffers work and flushes in fini (a network sink, a metrics exporter, an audit log) silently loses whatever it had queued at that moment.

Observed on v0.1.56; main still has the same code:

// pgdog/src/main.rs
fn install_sigterm_handler() {
    ...
    if let Ok(mut sigterm) = signal(SignalKind::terminate()) {
        tokio::spawn(async move {
            sigterm.recv().await;
            info!("🐕 PgDog is shutting down immediately [SIGTERM]");
            exit(0);
        });
    }
}

Reproduction

  1. Load a plugin whose fini logs a line and blocks briefly (or just logs).
  2. Start PgDog, then kill -TERM <pid>.
  3. The fini line never appears; exit status is 0. Sending SIGINT (graceful path) does log it.

Suggestion

Call plugin::shutdown() before exit(0) in the SIGTERM task, so fini runs on both paths, or route SIGTERM through the same shutdown sequence as SIGINT (possibly with the existing shutdown timeout so a misbehaving plugin cannot block the exit).

Workaround

Because the handler uses exit(0) rather than _exit, atexit(3) handlers do run. A plugin can register its flush with libc::atexit from its config/init hook (idempotent with fini). That is what we do now, but it depends on an implementation detail of the signal handler, so it would be better for PgDog to honor fini itself.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions