servicegroup

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 29, 2019 License: MIT Imports: 10 Imported by: 0

README

localytics/servicegroup

Golang HTTP server spin-up with best-practices safety in timeouts, debug endpoints, and graceful shutdown.

Go ships with a production-ready webserver you can spin up in a few lines of code… right? Well, it's close.

Servicegroup spins up a net/http server just as easily, but sets up:

  • Sensible timeouts and keepalives.
  • Debug endpoints (/debug/pprof) but on a different server/port (:6060 by default).
  • Graceful shutdown signal (ctrl+c/SIGINT, SIGKILL) handling without interrupting in-flight requests/responses.

This avoids the risks of slow requests DOSing your service, leaking debug info on public ports/endpoints, or normal server shutdowns leading to broken client requests.

Just bring your own http.Handler (from a basic http.ServeMux up to something like chi.Router) and wire it in:

	mux := http.NewServeMux()
	mux.HandleFunc("/ping", func(w http.ResponseWriter, req *http.Request) {fmt.Fprintf(w, "pong")}) 
	group := servicegroup.NewGroup(mux) // the main server (:8080 by default) binds to the handler/mux passed in here
	// Run() starts the servicegroup synchronously, and returns the error that terminated the group when it shuts down.
	err := group.Run()
    log.Printf("Servicegroup terminated due to initial worker termination: %s", err)

You can configure timeouts and ports by modifying the returned Group struct's fields before calling .Run().

Note that servicegroup does not handle TLS; the assumption is you're using this behind a load balancer or gateway that terminates SSL.

Example & Docs

You can view the godoc online.

See cmd/servicegroup-example-server for a runnable example.

How it Works

Servicegroup embeds a heptio workgroup.

If you have other goroutines you would like to mutually anchor to the lifecycle of the servicegroup (metrics reporters, loggers, background cleanup tasks, etc.), just add them with .Add(); see the heptio workgroup docs for details.

Running The Example Server
go run cmd/servicegroup-example-server/main.go

Then visit localhost:8080/work in a browser. Hit ctrl+c on the running server while the page is loading to see a graceful shutdown in action.

Or run the example in Docker:

docker build . -t servicegroup-example:latest
docker run --rm -p 8080:8080 -p 6060:6060 servicegroup-example:latest

Contributing & Development

Tests

You can use the provided go docker-compose service via docker-compose run to run one-offs in a container. Tests only:

docker-compose run --rm go test -v ./...

The full test suite and linters using the CI scripts:

docker-compose run --rm --entrypoint ci/checks.sh go

Note that if you use go run in Compose to run the servicegroup-example-server, SIGKILL won't propagate; you'll need to run a docker image with a built binary or test shutdown via SIGINT instead.

Code Style & Formatting

goimports is gofmt, but better. Set your editor up to run it on file save.

Documentation

Overview

Package servicegroup handles spinning up and gracefully shutting down a service by running a few linked goroutines: - Your service handler via an HTTP server (default at :8080) - The system default ServeMux with pprof enabled via an HTTP server (default at :6060) (:6060/debug/pprof) - Graceful shutdown routines that handles shutting both servers down - Sigint/sigkill listener to trigger graceful shutdown

When any goroutine in the group dies or sigint/sigkill is received, the others are killed off; the HTTP servers for the service and pprof handler are given a timeout (default 30 seconds) to finish before being forcibly shut down.

If you have other handlers you want exposed at :6060 as well (eg expvars) you can add them to the http default ServeMux before creating the workgroup or before calling .Run() on it.

Uses heptio/workgroup to manage lifecycle of our top-level permanently-running tasks. Influences: https://dave.cheney.net/practical-go/presentations/qcon-china.html#_never_start_a_goroutine_without_knowning_when_it_will_stop https://github.com/pseidemann/finish

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Group

type Group struct {
	workgroup.Group
	Handler                  http.Handler  // Handler for service HTTP server
	DebugServerAddr          string        // Port for default debug server to listen on (default ":6060")
	ServiceServerAddr        string        // Port for service server (handler passed to NewGroup) to listen on (default ":8080")
	ShutdownTimeout          time.Duration // Deadline for HTTP server graceful shutdown when interrupt is sent or any worker in the Group dies
	ServiceReadHeaderTimeout time.Duration // HTTP service header read timeout (default 30 seconds). http.Server.ReadHeaderTimeout: https://golang.org/pkg/net/http/#Server
	ServiceWriteTimeout      time.Duration // HTTP timeout for all post-header-read handling, including reading body and writing response (default 30 seconds). http.Server.WriteTimeout: https://golang.org/pkg/net/http/#Server
	ServiceIdleTimeout       time.Duration // HTTP connection idle timeout (default 30 seconds). http.Server.IdleTimeout: https://golang.org/pkg/net/http/#Server
}

Group is a workgroup.Group that includes some server-specific configuration values. It should be constructed via NewGroup().

func NewGroup

func NewGroup(handler http.Handler) Group

NewGroup sets up http.Servers configured to use the passed handler on :8080 and debug/metrics on :6060, and an OS interrupt listener for graceful shutdown.

Returns a servicegroup.Group that embeds a heptio/workgroup.Group ready to add more workers, or to call .Run().

Additional configuration of ports and timeouts can be set *before* .Run is called by setting parameters on the returned Group struct. Workers and http.Servers are only initialized and started after .Run() is called.

func (*Group) Run

func (g *Group) Run() error

Run starts the http.Servers for debug and the service using the Group's configured ports and timeouts, as well as any other workers you may have added to the Group.

Once running, if the system gets an interrupt or any Group worker is killed, the Group's graceful-shutdown workers will block until they gracefully shut down the HTTP servers, with a fallback to forcibly closing the servers after the ShutdownTimeout period elapses.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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