Skip to content

Commit

Permalink
feat: Add systemd readiness notification integration
Browse files Browse the repository at this point in the history
- Implemented a channel (`readyCh`) to signal application readiness to systemd
- Ensured robust handling of readiness signaling with error logging
  • Loading branch information
dyudin0821 committed Jun 21, 2024
1 parent d5dc86e commit d56853c
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 5 deletions.
20 changes: 20 additions & 0 deletions cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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")
Expand Down
23 changes: 18 additions & 5 deletions manager/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit d56853c

Please sign in to comment.