master
go 124 lines 2.61 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package agenthost
4
5 import (
6 "context"
7 "os"
8 "os/signal"
9 "sync"
10 "syscall"
11 "time"
12
13 "github.com/netdata/netdata/go/plugins/plugin/agent"
14 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
15 )
16
17 // Run hosts an agent process lifecycle (signals, restart, quit, metrics-audit timer).
18 func Run(a *agent.Agent) {
19 ch := make(chan os.Signal, 1)
20 signal.Notify(ch, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
21 signal.Ignore(syscall.SIGPIPE)
22
23 var keepAliveErr <-chan error
24 if !a.IsTerminalMode() {
25 ch := make(chan error, 1)
26 keepAliveErr = ch
27 go func() {
28 if err := a.RunKeepAlive(context.Background()); err != nil {
29 select {
30 case ch <- err:
31 default:
32 }
33 }
34 }()
35 }
36
37 var wg sync.WaitGroup
38 var exit bool
39 var finalizeReason string
40
41 var auditTimer *time.Timer
42 var auditTimerCh <-chan time.Time
43 if mode := a.AuditDuration(); mode > 0 {
44 auditTimer = time.NewTimer(mode)
45 auditTimerCh = auditTimer.C
46 defer auditTimer.Stop()
47 }
48
49 for {
50 collectorapi.ObsoleteCharts(true)
51
52 ctx, cancel := context.WithCancel(context.Background())
53 runDone := make(chan struct{})
54 wg.Go(func() {
55 defer close(runDone)
56 a.RunContext(ctx)
57 })
58
59 select {
60 case sig := <-ch:
61 switch sig {
62 case syscall.SIGHUP:
63 a.Infof("received %s signal (%d). Restarting running instance", sig, sig)
64 default:
65 a.Infof("received %s signal (%d). Terminating...", sig, sig)
66 exit = true
67 finalizeReason = sig.String()
68 }
69 case <-a.QuitCh():
70 a.Infof("received QUIT command. Terminating...")
71 exit = true
72 finalizeReason = "quit"
73 case <-auditTimerCh:
74 a.Infof("metrics-audit duration expired, finalizing metrics audit...")
75 exit = true
76 finalizeReason = "audit timer expired"
77 case <-keepAliveErr:
78 a.Info("too many keepAlive errors. Terminating...")
79 exit = true
80 finalizeReason = "keepalive error"
81 case <-runDone:
82 a.Info("agent run loop stopped. Terminating...")
83 exit = true
84 finalizeReason = "run loop stopped"
85 }
86
87 if exit {
88 collectorapi.ObsoleteCharts(false)
89 }
90
91 cancel()
92
93 stopped := func() bool {
94 timeout := time.Second * 10
95 t := time.NewTimer(timeout)
96 defer t.Stop()
97 done := make(chan struct{})
98
99 go func() { wg.Wait(); close(done) }()
100
101 select {
102 case <-t.C:
103 a.Errorf("stopping all goroutines timed out after %s. Exiting...", timeout)
104 return false
105 case <-done:
106 return true
107 }
108 }()
109
110 if !stopped {
111 if exit {
112 a.FinalizeMetricsAudit(finalizeReason + ", forced shutdown")
113 }
114 os.Exit(0)
115 }
116
117 if exit {
118 a.FinalizeMetricsAudit(finalizeReason)
119 os.Exit(0)
120 }
121
122 time.Sleep(time.Second)
123 }
124 }