Files
akvorado/common/daemon/root.go
Vincent Bernat 8be1bca4fd license: AGPL-3.0-only
```
git ls-files \*.js \*.go \
  | xargs sed -i '1i // SPDX-FileCopyrightText: 2022 Free Mobile\n// SPDX-License-Identifier: AGPL-3.0-only\n'
git ls-files \*.vue \
  | xargs sed -i '1i <!-- SPDX-FileCopyrightText: 2022 Free Mobile -->\n<!-- SPDX-License-Identifier: AGPL-3.0-only -->\n'
```
2022-06-29 11:42:28 +02:00

109 lines
2.3 KiB
Go

// SPDX-FileCopyrightText: 2022 Free Mobile
// SPDX-License-Identifier: AGPL-3.0-only
// Package daemon will handle daemon-related operations: readiness,
// watchdog, exit, reexec... Currently, only exit is implemented as
// other operations do not mean much when running in Docker.
package daemon
import (
"os"
"os/signal"
"syscall"
"gopkg.in/tomb.v2"
"akvorado/common/reporter"
)
// Component is the interface the daemon component provides.
type Component interface {
Start() error
Stop() error
Track(t *tomb.Tomb, who string)
// Lifecycle
Terminated() <-chan struct{}
Terminate()
}
// realComponent is a non-mock implementation of the Component
// interface.
type realComponent struct {
r *reporter.Reporter
tombs []tombWithOrigin
lifecycleComponent
}
// tombWithOrigin stores a reference to a tomb and its origin
type tombWithOrigin struct {
tomb *tomb.Tomb
origin string
}
// New will create a new daemon component.
func New(r *reporter.Reporter) (Component, error) {
return &realComponent{
r: r,
lifecycleComponent: lifecycleComponent{
terminateChannel: make(chan struct{}),
},
}, nil
}
// Start will make the daemon component active.
func (c *realComponent) Start() error {
// Listen for tombs
for _, t := range c.tombs {
go func(t tombWithOrigin) {
select {
case <-t.tomb.Dying():
if t.tomb.Err() == nil {
c.r.Debug().
Str("component", t.origin).
Msg("component shutting down, quitting")
} else {
c.r.Err(t.tomb.Err()).
Str("component", t.origin).
Msg("component error, quitting")
}
c.Terminate()
}
}(t)
}
// On signal, terminate
go func() {
signals := make(chan os.Signal, 1)
signal.Notify(signals,
syscall.SIGINT, syscall.SIGTERM)
select {
case s := <-signals:
c.r.Debug().Stringer("signal", s).Msg("signal received")
switch s {
case syscall.SIGINT, syscall.SIGTERM:
c.r.Info().Msg("quitting")
c.Terminate()
signal.Stop(signals)
}
case <-c.Terminated():
// Do nothing.
}
}()
return nil
}
// Stop will stop the component.
func (c *realComponent) Stop() error {
c.Terminate()
return nil
}
// Add a new tomb to be tracked. This is only used before Start().
func (c *realComponent) Track(t *tomb.Tomb, who string) {
c.tombs = append(c.tombs, tombWithOrigin{
tomb: t,
origin: who,
})
}