serverstarter

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 13, 2023 License: MIT Imports: 9 Imported by: 1

README

serverstarter Build Status Go Report Card GoDoc

serverstarter is a Go package which provides a server starter which can be used to do graceful restart.

A basic example

An example HTTP server which supports graceful restart.

package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/hnakamur/serverstarter"
)

func main() {
	addr := flag.String("addr", ":8080", "server listen address")
	flag.Parse()

	starter := serverstarter.New()
	if starter.IsMaster() {
		l, err := net.Listen("tcp", *addr)
		if err != nil {
			log.Fatalf("failed to listen %s; %v", *addr, err)
		}
		if err = starter.RunMaster(l); err != nil {
			log.Fatalf("failed to run master; %v", err)
		}
		return
	}

	listeners, err := starter.Listeners()
	if err != nil {
		log.Fatalf("failed to get listeners; %v", err)
	}
	l := listeners[0]

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "from pid %d.\n", os.Getpid())
	})

	srv := http.Server{}

	idleConnsClosed := make(chan struct{})
	go func() {
		sigterm := make(chan os.Signal, 1)
		signal.Notify(sigterm, syscall.SIGTERM)
		<-sigterm
		log.Printf("received sigterm")

		ctx, cancel := context.WithTimeout(context.Background(),
			*shutdownTimeout)
		defer cancel()
		srv.SetKeepAlivesEnabled(false)
		if err := srv.Shutdown(ctx); err != nil {
			// Error from closing listeners, or context timeout:
			log.Printf("cannot gracefully shut down the server: %v", err)
		}
		close(idleConnsClosed)
		log.Printf("closed idleConnsClosed")
	}()

	if err := starter.SendReady(); err != nil {
		log.Printf("failed to send ready: %v", err)
	}
	if err := srv.Serve(l); err != http.ErrServerClosed {
		// Error starting or closing listener:
		log.Printf("http server Serve: %v", err)
	}
	<-idleConnsClosed
}

A more advanced example

An example server which listens HTTP/1.1 and HTTP/2.0 ports simultaneously and supports graceful restart.

Build and run server
cd examples/graceserver
go build -race
./graceserver -http=:8080 -https=:8443 -pidfile=graceserver.pid
Keep repeating graceful restarts

In another terminal, run the following command.

cd examples/graceserver
watch -n 2 "kill -HUP $(cat graceserver.pid)"
Load test using github.com/tsenart/vegeta

In another terminal, run the following command.

$ go get -u github.com/tsenart/vegeta
$ printf "GET http://127.0.0.1:9090/\nGET https://127.0.0.1:9443/\n" | vegeta attack -duration=10s -rate=100 -insecure | vegeta report

Credits

Thanks!

Documentation

Overview

Package serverstarter provides a server starter which can be used to do graceful restart.

Example
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/hnakamur/serverstarter"
)

func main() {
	addr := flag.String("addr", ":8080", "server listen address")
	flag.Parse()

	starter := serverstarter.New()
	if starter.IsMaster() {
		l, err := net.Listen("tcp", *addr)
		if err != nil {
			log.Fatalf("failed to listen %s; %v", *addr, err)
		}
		log.Printf("master pid=%d start RunMaster", os.Getpid())
		if err = starter.RunMaster(l); err != nil {
			log.Fatalf("failed to run master; %v", err)
		}
		return
	}

	listeners, err := starter.Listeners()
	if err != nil {
		log.Fatalf("failed to get listeners; %v", err)
	}
	l := listeners[0]

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "from pid %d.\n", os.Getpid())
	})

	srv := http.Server{}

	idleConnsClosed := make(chan struct{})
	go func() {
		sigterm := make(chan os.Signal, 1)
		signal.Notify(sigterm, syscall.SIGTERM)
		<-sigterm

		log.Printf("received sigterm")
		// We received an interrupt signal, shut down.
		if err := srv.Shutdown(context.Background()); err != nil {
			// Error from closing listeners, or context timeout:
			log.Printf("http(s) server Shutdown: %v", err)
		}
		close(idleConnsClosed)
		log.Printf("closed idleConnsClosed")
	}()

	if err := starter.SendReady(); err != nil {
		log.Printf("failed to send ready: %v", err)
	}
	log.Printf("worker pid=%d http server start Serve", os.Getpid())
	if err := srv.Serve(l); err != http.ErrServerClosed {
		// Error starting or closing listener:
		log.Printf("http server Serve: %v", err)
	}
	<-idleConnsClosed
	log.Printf("exiting pid=%d", os.Getpid())
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Option

type Option func(s *Starter)

Option is the type for configuring a Starter.

func SetChildShutdownWaitTimeout

func SetChildShutdownWaitTimeout(timeout time.Duration) Option

SetChildShutdownWaitTimeout sets the timeout for waiting child to shutdown gracefully. If no SetChildShutdownWaitTimeout is called, the default value is time.Minute.

func SetEnvName

func SetEnvName(name string) Option

SetEnvName sets the environment variable name for passing the listener file descriptor count to the worker process. When this options is not called, the environment variable name will be "LISTEN_FDS".

func SetGracefulShutdownSignalToChild

func SetGracefulShutdownSignalToChild(sig syscall.Signal) Option

SetGracefulShutdownSignalToChild sets the signal to send to child for graceful shutdown. If no SetGracefulShutdownSignalToChild is called, the default value is syscall.SIGTERM.

type Starter

type Starter struct {
	// contains filtered or unexported fields
}

Starter is a server starter.

func New

func New(options ...Option) *Starter

New returns a new Starter.

func (*Starter) IsMaster

func (s *Starter) IsMaster() bool

IsMaster returns whether this process is the master or not. It returns true if this process is the master, and returns false if this process is the worker.

func (*Starter) Listeners

func (s *Starter) Listeners() ([]net.Listener, error)

Listeners returns the listeners passed from the master if this is called by the worker process. It returns nil when this is called by the master process.

func (*Starter) RunMaster

func (s *Starter) RunMaster(listeners ...net.Listener) error

RunMaster starts a worker process and run the loop for starting and stopping the worker on signals.

If the master process receives a SIGHUP, it starts a new worker and stop the old worker by sending a signal set by SetGracefulShutdownSignalToChild. If the master process receives a SIGINT or a SIGTERM, it sends the SIGTERM to the worker and exists.

func (*Starter) SendReady

func (s *Starter) SendReady() error

SendReady sends ready notification from child to parent.

Directories

Path Synopsis
examples
graceserver
An example HTTP/1.1 and HTTP/2.0 server which supports graceful restart
An example HTTP/1.1 and HTTP/2.0 server which supports graceful restart

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL