Package server

import "funnyhaha.technology/httpkit/server"
View the source code

Overview

Package server runs an HTTP API with the timeouts, health checks and graceful shutdown that every service needs.

A Server has two listeners. The public one serves the API. The internal one, which mustn't be exposed outside the cluster, serves:

Wire it in main, and run it until a signal:

ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
err := server.New(api).WithLogger(logger).Server().Run(ctx)

When ctx is cancelled, Run shuts down gracefully: it fails /readyz, waits the drain delay so load balancers stop sending requests, then lets in-flight requests finish within the shutdown timeout.

Index

Constants

const (
	DefaultAddr              = ":8080"
	DefaultInternalAddr      = ":9090"
	DefaultReadHeaderTimeout = 5 * time.Second
	DefaultReadTimeout       = 30 * time.Second
	DefaultWriteTimeout      = 30 * time.Second
	DefaultIdleTimeout       = 120 * time.Second
	DefaultMaxHeaderBytes    = 64 << 10
	DefaultDrainDelay        = 5 * time.Second
	DefaultShutdownTimeout   = 20 * time.Second
)
source

Defaults, used unless a With method changes them.

Variables

var ErrShutdownTimeout = errors.New("shutdown timed out")
source

ErrShutdownTimeout is returned by Server.Run when requests are still in flight after the shutdown timeout. They're cancelled.

Functions

Draining source

func Draining(ctx context.Context) <-chan struct{}

Draining returns a channel that's closed when the server that's handling the request starts shutting down. A handler that streams indefinitely should end its stream then, so the client reconnects to another instance; shutdown otherwise waits for it until the timeout. It returns nil, which never closes, outside a Server.

Types

Builder source

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

Builder configures a Server. Its With methods return a modified copy.

New source

func New(api http.Handler) Builder

New returns a Builder for a server that serves api. It panics if api is nil.

(Builder) Server source

func (b Builder) Server() *Server

Server returns the configured server.

(Builder) WithAddr source

func (b Builder) WithAddr(addr string) Builder

WithAddr sets the public listener's address, such as ":8080".

(Builder) WithDrainDelay source

func (b Builder) WithDrainDelay(d time.Duration) Builder

WithDrainDelay sets how long Run waits, after failing /readyz, before it stops accepting connections. It should be longer than the load balancer's readiness check interval.

(Builder) WithIdleTimeout source

func (b Builder) WithIdleTimeout(d time.Duration) Builder

WithIdleTimeout sets how long an idle keep-alive connection is kept open.

(Builder) WithInternalAddr source

func (b Builder) WithInternalAddr(addr string) Builder

WithInternalAddr sets the internal listener's address, such as ":9090".

(Builder) WithLogger source

func (b Builder) WithLogger(logger *slog.Logger) Builder

WithLogger sets the logger for the server's own messages and for errors from net/http.

(Builder) WithMaxHeaderBytes source

func (b Builder) WithMaxHeaderBytes(n int) Builder

WithMaxHeaderBytes sets the largest request header net/http reads. Larger requests get a 431 (RFC 6585, Section 5).

(Builder) WithReadHeaderTimeout source

func (b Builder) WithReadHeaderTimeout(d time.Duration) Builder

WithReadHeaderTimeout sets how long a client may take to send the request headers.

(Builder) WithReadTimeout source

func (b Builder) WithReadTimeout(d time.Duration) Builder

WithReadTimeout sets how long a client may take to send the whole request.

(Builder) WithShutdownTimeout source

func (b Builder) WithShutdownTimeout(d time.Duration) Builder

WithShutdownTimeout sets how long Run waits for in-flight requests to finish before cancelling them.

(Builder) WithWriteTimeout source

func (b Builder) WithWriteTimeout(d time.Duration) Builder

WithWriteTimeout sets how long a handler may take to write its response, from the end of the request headers. A handler that streams extends its own deadline with http.ResponseController.

Server source

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

Server is an API server with its internal listener. Build one with New.

(Server) Addr source

func (s *Server) Addr() net.Addr

Addr returns the public listener's address, or nil before Listen.

(Server) InternalAddr source

func (s *Server) InternalAddr() net.Addr

InternalAddr returns the internal listener's address, or nil before Listen.

(Server) Listen source

func (s *Server) Listen(ctx context.Context) error

Listen binds both listeners, so that Server.Addr and Server.InternalAddr report the addresses actually bound, such as the port chosen for ":0". Run calls it if it hasn't been called.

(Server) Run source

func (s *Server) Run(ctx context.Context) error

Run serves until ctx is cancelled, then shuts down gracefully:

  1. /readyz starts failing with 503, and handlers' Draining channels close.
  2. Run waits the drain delay, while still serving requests.
  3. Both listeners stop accepting connections, and in-flight requests have the shutdown timeout to finish.
  4. Any still running have their contexts cancelled, and Run returns ErrShutdownTimeout.

It returns nil after a clean shutdown, or an error if a listener fails. A Server can be run only once.