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  }