-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmain.go
152 lines (121 loc) · 3.59 KB
/
main.go
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package main
import (
"context"
"fmt"
"math/rand"
"net/http"
"os"
"os/signal"
"time"
"github.com/Noah-Huppert/human-call-filter/calls"
"github.com/Noah-Huppert/human-call-filter/config"
"github.com/Noah-Huppert/human-call-filter/dashboard"
"github.com/Noah-Huppert/human-call-filter/libdb"
"github.com/Noah-Huppert/golog"
)
func main() {
// Context
ctx, cancelFn := context.WithCancel(context.Background())
// Logger
logger := golog.NewStdLogger("human-call-filter")
// Setup exit handler
exitSigChan := make(chan os.Signal, 1)
signal.Notify(exitSigChan, os.Interrupt)
go func() {
<-exitSigChan
cancelFn()
}()
// Load application configuration
cfg, err := config.LoadConfig()
if err != nil {
logger.Fatalf("error loading configuration: %s", err.Error())
}
// Seed random number generator
rand.Seed(time.Now().UnixNano())
// Connect to database
db, err := libdb.ConnectX(cfg.DBConfig)
if err != nil {
logger.Fatalf("error connecting to database: %s", err.Error())
}
// waitChan is used to wait for http servers to shut down, a nil on the
// channel is a success. Otherwise the shutdown error is sent.
waitChan := make(chan WaitEntry)
totalWaitEntries := 2
receivedWaitEntries := 0
// Setup twilio call handler server
callServer := calls.NewServer(logger, cfg, db)
shutdownHTTPServerOnExit("calls", ctx, waitChan, &callServer)
logger.Debugf("starting calls http server on %s", callServer.Addr)
startHTTPServer("calls", waitChan, &callServer)
// Setup dashboard server
dashboardServer := dashboard.NewServer(logger, cfg, db)
shutdownHTTPServerOnExit("dashboard", ctx, waitChan, &dashboardServer)
logger.Debugf("starting dashboard http server on %s", dashboardServer.Addr)
startHTTPServer("dashboard", waitChan, &dashboardServer)
// Wait for servers to exit
ctxDone := false
for receivedWaitEntries < totalWaitEntries {
select {
case <-ctx.Done():
ctxDone = true
case waitEntry := <-waitChan:
if waitEntry.err != nil {
logger.Errorf("error running %s: %s", waitEntry.name, err.Error())
// Cancel context if not canceled already, so that other jobs
// shut down
if !ctxDone {
cancelFn()
}
} else {
logger.Debugf("%s successfully completed", waitEntry.name)
}
receivedWaitEntries++
}
}
}
// WaitEntry holds information about the status of an asynchronous job
type WaitEntry struct {
// name identifies the job
name string
// err holds an error if one occurs while running the job, nil if the job
// completed successfully
err error
}
// startHTTPServer starts an http server in a go routine and exits if there is
// an error.
//
// The name argument is used to identify the http server if an error occurs.
func startHTTPServer(name string, waitChan chan<- WaitEntry, server *http.Server) {
go func() {
err := server.ListenAndServe()
if err != nil && err != http.ErrServerClosed {
waitChan <- WaitEntry{
name: name,
err: fmt.Errorf("error running http server: %s", err.Error()),
}
}
}()
}
// shutdownHTTPServerOnExit starts a go routine which waits for a Context to
// close and then gracefully shuts down an http.Server.
//
// The name argument will be used to identify the http server if an error
// occurs.
func shutdownHTTPServerOnExit(name string, ctx context.Context,
waitChan chan<- WaitEntry, server *http.Server) {
go func() {
<-ctx.Done()
err := server.Shutdown(context.Background())
if err != nil {
waitChan <- WaitEntry{
name: name,
err: fmt.Errorf("failed to shutdown the http server: %s",
err.Error()),
}
}
waitChan <- WaitEntry{
name: name,
err: nil,
}
}()
}