Skip to main content

AlmaForge Signals Reference

almad installs a signal handler that responds to a small set of Unix signals. Each signal triggers a specific operational action: graceful shutdown, fast shutdown, diagnostic dump, or a fork-based graceful upgrade. Signals outside the handled set follow the operating system and Go runtime's behavior.

Sending a signal​

Send a signal by name to the almad PID:

Terminal
sudo kill -SIGHUP $(pidof almad)

Or with a systemd unit:

Terminal
sudo systemctl kill --kill-whom=main -s HUP almad.service

Signals are processed sequentially by a single goroutine in almad, so two signals delivered back-to-back run one after the other, not in parallel.

Handled signals​

SignalBehavior
SIGQUITGraceful shutdown. Stops accepting new connections and waits for in-flight work to finish before exiting. No time limit.
SIGTERMFast shutdown with a deadline. Starts a graceful shutdown but exits after the shutdown timeout (3 seconds by default) even if connections are still open.
SIGINTIdentical to SIGTERM (what Ctrl-C sends to a foreground almad).
SIGHUPGraceful restart. Forks a new almad process to take over the listeners, then gracefully shuts down the old one after the new process is running.
SIGUSR2Forks a new almad process without shutting down the old one. Used internally by SIGHUP and rarely sent on its own.
SIGUSR1Writes a diagnostic dump (goroutine traces, recent errors, process internals) to the daemon's stderr. The process keeps running.

SIGCHLD is handled internally to reap child processes spawned during SIGHUP / SIGUSR2 upgrades. Operators should not send it explicitly.

Any signal not listed above, including SIGKILL, is not handled by almad. SIGKILL cannot be intercepted by any Unix process. The kernel terminates almad immediately without running shutdown handlers, dropping every in-flight session.

Operational use cases​

Graceful shutdown during maintenance​

Use SIGQUIT when you need almad to finish draining every active session before exiting, and you are willing to wait however long that takes. There is no upper bound on the drain window. A long-running alma ssh session keeps the process alive until the user disconnects.

Terminal
sudo kill -SIGQUIT $(pidof almad)

Fast shutdown when you cannot wait​

SIGTERM is what systemctl stop sends by default. almad starts a graceful drain but gives up after the shutdown timeout (3 seconds) and exits. Active sessions are dropped when the timeout expires.

Zero-downtime upgrade​

SIGHUP starts a replacement process from the binary on disk and re-reads resource files at startup. The child inherits the running process's environment and command-line arguments. Changes to a systemd environment file require a systemd restart instead. See Upgrades for the rolling procedure.

Sequence:

  1. Replace the binary or resource files on disk.
  2. Send SIGHUP to the running almad PID.
  3. almad forks a new child process that inherits the listening sockets, waits for the child to signal readiness, then starts a graceful shutdown on the old process.
  4. Existing connections continue to be served by the old process until they finish. New connections are accepted by the new process from the moment it is up.

This works because parent and child share the same listening sockets. No client observes a dropped connection during the handover.

Diagnostic dump without a restart​

SIGUSR1 writes a one-shot diagnostic snapshot to the daemon's standard error stream. Useful when a process is stuck and you want goroutine traces, internal state, and recent error history without stopping the service.

Terminal
sudo kill -SIGUSR1 $(pidof almad)sudo journalctl -u almad.service --since="5 minutes ago"

For continuous runtime profiling, enable the diagnostic listener with --diag-listen (or ALMA_DIAG_LISTEN), start the process with --debug, which is what registers the handlers, and scrape /debug/pprof/* instead. SIGUSR1 is for one-off captures, not ongoing observability.

Unrecognized signals​

Only the signals listed above are registered with the daemon's handler. Other signals retain their operating-system and Go runtime semantics. In particular, SIGKILL immediately terminates the process and SIGSTOP suspends it. Neither can be caught or ignored by the daemon.