@@ -2,43 +2,97 @@ package main
2
2
3
3
import (
4
4
"context"
5
+ "errors"
6
+ "fmt"
5
7
"log"
6
8
"net/http"
9
+ "os"
10
+ "os/signal"
11
+ "syscall"
7
12
"time"
8
13
)
9
14
10
15
func main () {
16
+ log .SetFlags (log .Lmicroseconds )
17
+
18
+ if err := run (); err != nil {
19
+ log .Fatalf ("Application failed: %v" , err )
20
+ }
21
+ }
22
+
23
+ func run () error {
11
24
var (
12
- mux = http .NewServeMux ()
13
- srv = & http.Server {Addr : ":8888" , Handler : mux }
14
- mainCtx = context .Background ()
15
- procCtx , procCxl = context .WithTimeout (mainCtx , 3 * time .Second )
25
+ port string
16
26
)
17
- defer procCxl ()
27
+ if port = os .Getenv ("PORT" ); port == "" {
28
+ port = "8888"
29
+ }
18
30
19
- // ----------- Start ----------- //
31
+ var (
32
+ mux = http .NewServeMux ()
33
+ srv = & http.Server {
34
+ Addr : ":" + port ,
35
+ Handler : mux ,
36
+ MaxHeaderBytes : 1 << 20 , // 1MB
37
+ ReadTimeout : 10 * time .Second ,
38
+ WriteTimeout : 10 * time .Second ,
39
+ IdleTimeout : 120 * time .Second ,
40
+ }
41
+ mainCtx , mainCxl = context .WithCancel (context .Background ())
42
+ errs = make (chan error , 1 )
43
+ )
44
+ defer mainCxl ()
20
45
46
+ // ----------- Handlers ----------- //
47
+ mux .HandleFunc ("/" , func (w http.ResponseWriter , r * http.Request ) {
48
+ fmt .Fprintln (w , "Hello World" )
49
+ })
50
+
51
+ // ----------- Start ----------- //
21
52
go func () {
22
- log .Println ("Server is up." )
23
- srv .ListenAndServe ()
53
+ log .Printf ("Server is listening on %s" , srv .Addr )
54
+ if err := srv .ListenAndServe (); err != nil {
55
+ errs <- err
56
+ }
24
57
}()
25
58
26
- <- procCtx .Done ()
27
-
28
- // ----------- Shutdown ----------- //
29
-
59
+ // ----------- Signals ----------- //
30
60
var (
31
- shutdownCtx , shutdownCxl = context . WithTimeout ( mainCtx , 1 * time . Second )
61
+ sigs = make ( chan os. Signal , 1 )
32
62
)
33
- defer shutdownCxl ( )
34
-
35
- if err := srv . Shutdown ( shutdownCtx ); err != nil {
36
- switch err {
37
- case context . DeadlineExceeded :
38
- log . Println ( "Server shutdown process timed out." )
39
- default :
40
- log . Fatal ( err )
63
+ signal . Notify ( sigs , syscall . SIGINT , syscall . SIGTERM , syscall . SIGHUP )
64
+ defer signal . Stop ( sigs )
65
+
66
+ // ----------- Selects ----------- //
67
+ select {
68
+ case err := <- errs :
69
+ if ! errors . Is ( err , http . ErrServerClosed ) {
70
+ return fmt . Errorf ( "server error: %w" , err )
41
71
}
72
+ return nil
73
+ case sig := <- sigs :
74
+ log .Printf ("Shutdown started: %v" , sig )
75
+
76
+ // ----------- Shutdown ----------- //
77
+ shutCtx , shutCxl := context .WithTimeout (mainCtx , 5 * time .Second )
78
+ defer shutCxl ()
79
+
80
+ if err := srv .Shutdown (shutCtx ); err != nil {
81
+ if errors .Is (err , context .DeadlineExceeded ) {
82
+ log .Println ("Server shutdown process timed out." )
83
+ } else {
84
+ log .Printf ("Server shutdown failed: %v" , err )
85
+ }
86
+
87
+ if closeErr := srv .Close (); closeErr != nil {
88
+ return fmt .Errorf ("force close failed: %w" , closeErr )
89
+ }
90
+
91
+ return fmt .Errorf ("shutdown error: %w" , err )
92
+ }
93
+
94
+ log .Println ("Server has been gracefully shutdown." )
95
+
96
+ return nil
42
97
}
43
- log .Println ("Server has been shutdown." )
44
98
}
0 commit comments