-
-
Notifications
You must be signed in to change notification settings - Fork 62
Expand file tree
/
Copy pathmain.go
More file actions
102 lines (86 loc) · 2.42 KB
/
Copy pathmain.go
File metadata and controls
102 lines (86 loc) · 2.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package main
import (
"context"
"fmt"
"os"
"time"
"github.com/naughtygopher/errors"
"github.com/naughtygopher/proberesponder"
"github.com/naughtygopher/goapp/internal/configs"
"github.com/naughtygopher/goapp/internal/pkg/logger"
"github.com/naughtygopher/goapp/internal/pkg/sysignals"
)
// recoverer is used for panic recovery of the application (note: this is not for the HTTP/gRPC servers).
// So that even if the main function panics we can produce required logs for troubleshooting
var exitErr error
func recoverer() {
exitCode := 0
var exitInfo any
rec := recover()
err, _ := rec.(error)
if err != nil {
exitCode = 1
exitInfo = err
} else if rec != nil {
exitCode = 2
exitInfo = rec
} else if exitErr != nil {
exitCode = 3
exitInfo = exitErr
}
// exiting after receiving a quit signal can be considered a *clean/successful* exit
if errors.Is(exitErr, sysignals.ErrSigQuit) {
exitCode = 0
}
ctx := context.Background()
// logging this because we have info logs saying "listening to" various port numbers
// based on the server type (gRPC, HTTP etc.). But it's unclear *from the logs*
// if the server is up and running, if it exits for any reason
if exitCode == 0 {
logger.Info(ctx, fmt.Sprintf("shutdown complete: %+v", exitInfo))
} else {
logger.Error(ctx, fmt.Sprintf("shutdown complete (exit: %d): %+v", exitCode, exitInfo))
}
os.Exit(exitCode)
}
func main() {
defer recoverer()
var (
ctx = context.Background()
fatalErr = make(chan error, 1)
shutdownGraceperiod = time.Minute
probeInterval = time.Second * 3
probestatus = proberesponder.New()
)
cfgs, err := configs.New()
if err != nil {
panic(errors.Wrap(err))
}
logger.UpdateDefaultLogger(logger.New(
cfgs.AppName, cfgs.AppVersion, 0,
map[string]string{
"env": cfgs.Environment.String(),
}),
)
// This needs to remain after log initialisation and before server initialisation.
ap := startAPM(ctx, cfgs)
healthResponder, err := startHealthResponder(ctx, probestatus, fatalErr)
if err != nil {
panic(err)
}
hserver, gserver := start(ctx, probestatus, cfgs, fatalErr)
// by now all the intended servers, subscribers etc. are up and running.
probestatus.SetNotStarted(false)
probestatus.SetNotReady(false)
probestatus.SetNotLive(false)
defer shutdown(
shutdownGraceperiod,
probeInterval,
probestatus,
healthResponder,
hserver,
gserver,
ap,
)
exitErr = <-fatalErr
}