github.com/cornelk/go-cloud@v0.17.1/server/example_test.go (about) 1 // Copyright 2019 The Go Cloud Development Kit Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package server_test 16 17 import ( 18 "context" 19 "errors" 20 "fmt" 21 "log" 22 "net/http" 23 "os" 24 "os/signal" 25 "sync" 26 "time" 27 28 "github.com/cornelk/go-cloud/server" 29 30 "github.com/cornelk/go-cloud/server/health" 31 "github.com/cornelk/go-cloud/server/requestlog" 32 ) 33 34 func ExampleServer_New() { 35 // PRAGMA: This example is used on github.com/cornelk/go-cloud; PRAGMA comments adjust how it is shown and can be ignored. 36 37 // Use the constructor function to create the server. 38 srv := server.New(http.DefaultServeMux, nil) 39 40 // Register a route. 41 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 42 fmt.Fprintln(w, "Hello, World!") 43 }) 44 45 // Start the server. If ListenAndServe returns an error, print it and exit. 46 if err := srv.ListenAndServe(":8080"); err != nil { 47 log.Fatalf("%v", err) 48 } 49 } 50 51 func ExampleServer_RequestLogger() { 52 // PRAGMA: This example is used on github.com/cornelk/go-cloud; PRAGMA comments adjust how it is shown and can be ignored. 53 54 // Create a logger, and assign it to the RequestLogger field of a 55 // server.Options struct. 56 srvOptions := &server.Options{ 57 RequestLogger: requestlog.NewNCSALogger(os.Stdout, func(error) {}), 58 } 59 60 // Pass the options to the Server constructor. 61 srv := server.New(http.DefaultServeMux, srvOptions) 62 63 // Register a route. 64 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 65 fmt.Fprintln(w, "Hello, World!") 66 }) 67 68 // Start the server. You will see requests logged to STDOUT. 69 if err := srv.ListenAndServe(":8080"); err != nil { 70 log.Fatalf("%v", err) 71 } 72 } 73 74 // customHealthCheck is an example health check. It implements the 75 // health.Checker interface and reports the server is healthy when the healthy 76 // field is set to true. 77 type customHealthCheck struct { 78 mu sync.RWMutex 79 healthy bool 80 } 81 82 // customHealthCheck implements the health.Checker interface because it has a 83 // CheckHealth method. Because each application may have a different definition 84 // of what it means to be "healthy", you will need to define a CheckHealth method 85 // specific to your application. 86 func (h *customHealthCheck) CheckHealth() error { 87 h.mu.RLock() 88 defer h.mu.RUnlock() 89 if !h.healthy { 90 return errors.New("not ready yet!") 91 } 92 return nil 93 } 94 func ExampleServer_HealthChecks() { 95 // PRAGMA: This example is used on github.com/cornelk/go-cloud; PRAGMA comments adjust how it is shown and can be ignored. 96 97 // Create a health.Checker from the type we defined for our application. 98 // In this example, healthCheck will report the server is unhealthy for 10 seconds 99 // after startup, and as healthy henceforth. Check the /healthz/readiness 100 // HTTP path to see readiness. 101 healthCheck := new(customHealthCheck) 102 time.AfterFunc(10*time.Second, func() { 103 healthCheck.mu.Lock() 104 defer healthCheck.mu.Unlock() 105 healthCheck.healthy = true 106 }) 107 108 // The server.Options struct takes a slice of health checks, because you 109 // may need to check several things. 110 srvOptions := &server.Options{ 111 HealthChecks: []health.Checker{healthCheck}, 112 } 113 114 // Pass the options to the Server constructor. 115 srv := server.New(http.DefaultServeMux, srvOptions) 116 117 // Register a route. 118 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 119 fmt.Fprintln(w, "Hello, World!") 120 }) 121 122 // Start the server. You will see requests logged to STDOUT. 123 if err := srv.ListenAndServe(":8080"); err != nil { 124 log.Fatalf("%v", err) 125 } 126 } 127 128 func ExampleServer_Shutdown() { 129 // OPTIONAL: Specify a driver in the options for the constructor. 130 // NewDefaultDriver will be used by default if it is not explicitly set, and 131 // uses http.Server with read, write, and idle timeouts set. When Shutdown 132 // is called on the server, it is called on the driver. 133 srvOptions := &server.Options{ 134 Driver: server.NewDefaultDriver(), 135 } 136 137 // Pass the options to the Server constructor. 138 srv := server.New(http.DefaultServeMux, srvOptions) 139 140 // If your application will be behind a load balancer that handles graceful 141 // shutdown of requests, you may not need to call Shutdown on the server 142 // directly. If you need to ensure graceful shutdown directly, it is important 143 // to have a separate goroutine, because ListenAndServe blocks indefinitely. 144 go func() { 145 interrupt := make(chan os.Signal, 1) 146 signal.Notify(interrupt, os.Interrupt) 147 // Receive off the chanel in a loop, because the interrupt could be sent 148 // before ListenAndServe starts. 149 for { 150 <-interrupt 151 srv.Shutdown(context.Background()) 152 } 153 }() 154 155 // Register a route. 156 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 157 fmt.Fprintln(w, "Hello, World!") 158 }) 159 160 // Start the server. You will see requests logged to STDOUT. 161 // In the absence of an error, ListenAndServe blocks forever. 162 if err := srv.ListenAndServe(":8080"); err != nil { 163 log.Fatalf("%v", err) 164 } 165 }