From d56853c08519b060d9bce60ad6b9c740782f7e0f Mon Sep 17 00:00:00 2001 From: Denis Yudin Date: Fri, 21 Jun 2024 13:29:10 +0400 Subject: [PATCH] feat: Add systemd readiness notification integration - Implemented a channel (`readyCh`) to signal application readiness to systemd - Ensured robust handling of readiness signaling with error logging --- cli.go | 20 ++++++++++++++++++++ manager/runner.go | 23 ++++++++++++++++++----- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/cli.go b/cli.go index 7a6bd3302..09e4b0f9f 100644 --- a/cli.go +++ b/cli.go @@ -13,6 +13,7 @@ import ( "sync" "time" + "github.com/coreos/go-systemd/v22/daemon" "github.com/hashicorp/consul-template/config" "github.com/hashicorp/consul-template/logging" "github.com/hashicorp/consul-template/manager" @@ -105,11 +106,29 @@ func (cli *CLI) Run(args []string) int { return ExitCodeOK } + // Create a channel for signaling readiness to the systemd init system. + readyCh := make(chan struct{}) + + // Start a goroutine that listens for signals on the readyCh channel. + // When a signal (an empty struct) is received, it notifies systemd that + // the application is ready by calling daemon.SdNotify with SdNotifyReady. + // If an error occurs during the notification, it logs a warning message. + go func() { + for range readyCh { + _, err := daemon.SdNotify(false, daemon.SdNotifyReady) + if err != nil { + log.Printf("[WARN] failed to signal readiness to systemd: %v", err) + } + } + }() + // Initial runner runner, err := manager.NewRunner(config, dry) if err != nil { return logError(err, ExitCodeRunnerError) } + + runner.SetReadyChannel(readyCh) go runner.Start() // Listen for monitored signals @@ -163,6 +182,7 @@ func (cli *CLI) Run(args []string) int { if err != nil { return logError(err, ExitCodeRunnerError) } + runner.SetReadyChannel(readyCh) go runner.Start() case *config.KillSignal: fmt.Fprintf(cli.errStream, "Cleaning up...\n") diff --git a/manager/runner.go b/manager/runner.go index eb021cf4f..8c16c727b 100644 --- a/manager/runner.go +++ b/manager/runner.go @@ -23,7 +23,6 @@ import ( "github.com/hashicorp/consul-template/template" "github.com/hashicorp/consul-template/watch" - "github.com/coreos/go-systemd/v22/daemon" "github.com/hashicorp/go-multierror" ) @@ -133,6 +132,12 @@ type Runner struct { // Runner config. This prevents risk of data races when reading config for // other elements started by the Runner, like template functions. finalConfigCopy config.Config + + // readyCh is a channel used to signal readiness to the systemd init system. + // When a struct{} is sent on this channel, it triggers a notification to systemd + // that the application is ready. This helps in managing application state and + // integration with systemd's readiness protocol. + readyCh chan struct{} } // RenderEvent captures the time and events that occurred for a template @@ -311,10 +316,11 @@ func (r *Runner) Start() { if r.allTemplatesRendered() { log.Printf("[DEBUG] (runner) all templates rendered") - // Send a signal to systemd that we are ready. - _, err := daemon.SdNotify(false, daemon.SdNotifyReady) - if err != nil { - log.Printf("[WARN] (runner) failed to signal readiness to systemd: %v", err) + // If the readyCh channel is not nil, send an empty struct to signal readiness. + // This will notify the systemd init system that the application is ready to + // handle requests. This mechanism integrates with systemd's readiness protocol. + if r.readyCh != nil { + r.readyCh <- struct{}{} } // Enable quiescence for all templates if we have specified wait @@ -730,6 +736,13 @@ func (r *Runner) Run() error { return nil } +// SetReadyChannel sets the readyCh channel which is used to signal readiness to the systemd init system. +// The channel should be a struct{} channel, and when an empty struct is sent on this channel, +// it will trigger a notification to systemd that the application is ready. +func (r *Runner) SetReadyChannel(ch chan struct{}) { + r.readyCh = ch +} + type templateRunCtx struct { // commands is the set of commands that will be executed after all templates // have run. When adding to the commands, care should be taken not to