From 5aa1ff17256c4e7de7279c35915a4f8a4d149671 Mon Sep 17 00:00:00 2001 From: Daniel Collins Date: Wed, 14 May 2025 22:52:41 +0100 Subject: [PATCH] [PROTOTYPE] Inform agent-shutdown hook of reason for agent shutdown. When running the agent-shutdown hook, the following environment variables may be set: - BUILDKITE_AGENT_SHUTDOWN_REASON: The reason the buildkite-agent process is shutting down, "IDLE" for the idle timeout expiring or "SIGNAL" for SIGINT/SIGTERM/etc. - BUILDKITE_AGENT_SHUTDOWN_SIGNAL: The signal which caused the agent to shut down (e.g. "SIGINT"). My use case for this is triggering a system shutdown from the agent shutdown hook when the agent has shut down due to inactivity, I can imagine it getting used for other cluster orchestration things too. --- agent/agent_worker.go | 2 ++ clicommand/agent_start.go | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/agent/agent_worker.go b/agent/agent_worker.go index 4fc9124046..b8170128c2 100644 --- a/agent/agent_worker.go +++ b/agent/agent_worker.go @@ -7,6 +7,7 @@ import ( "io" "math/rand/v2" "net/http" + "os" "sync" "time" @@ -424,6 +425,7 @@ func (a *AgentWorker) runPingLoop(ctx context.Context, idleMonitor *IdleMonitor) // But only terminate if everyone else is also idle if idleMonitor.Idle() { a.logger.Info("All agents have been idle for %v. Disconnecting...", disconnectAfterIdleTimeout) + os.Setenv("BUILDKITE_AGENT_SHUTDOWN_REASON", "IDLE") return nil } a.logger.Debug("Agent has been idle for %.f seconds, but other agents haven't", diff --git a/clicommand/agent_start.go b/clicommand/agent_start.go index e8c4e82b03..07533cbb29 100644 --- a/clicommand/agent_start.go +++ b/clicommand/agent_start.go @@ -1377,9 +1377,17 @@ func handlePoolSignals(ctx context.Context, l logger.Logger, pool *agent.AgentPo switch sig { case syscall.SIGQUIT: l.Debug("Received signal `%s`", sig.String()) + os.Setenv("BUILDKITE_AGENT_SHUTDOWN_REASON", "SIGNAL") + os.Setenv("BUILDKITE_AGENT_SHUTDOWN_SIGNAL", "SIGQUIT") pool.Stop(false) case syscall.SIGTERM, syscall.SIGINT: l.Debug("Received signal `%s`", sig.String()) + os.Setenv("BUILDKITE_AGENT_SHUTDOWN_REASON", "SIGNAL") + if sig == syscall.SIGTERM { + os.Setenv("BUILDKITE_AGENT_SHUTDOWN_SIGNAL", "SIGTERM") + } else { + os.Setenv("BUILDKITE_AGENT_SHUTDOWN_SIGNAL", "SIGINT") + } if interruptCount == 0 { interruptCount++ l.Info("Received CTRL-C, send again to forcefully kill the agent(s)")