idletracker

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Dec 9, 2020 License: BSD-3-Clause Imports: 5 Imported by: 0

README

IdleTracker: Close Idle Server Instances

PkgGoDev

Once the http.Server you'd typically use this in has not received new connections for some time, the context IdleTracker implements is done and can be used to initiate an orderly shutdown.

Works best with systemd's socket-activated services*.

Example

An excerpt from my extended godoc:

import (
	"github.com/coreos/go-systemd/v22/activation"
	"github.com/wmark/idletracker"
)

var (
	httpAddr = flag.String("http", "[::1]:8080", "HTTP service address")
)

func main() {
	flag.Parse()

	ctx, cancelFn := context.WithCancel(context.Background())
	server := &http.Server{
		Handler:      handler, // http.NewServeMux()
		ReadTimeout:  15 * time.Second,
		WriteTimeout: 15 * time.Second,
		IdleTimeout:  2 * time.Minute,
	}

	var ln net.Listener
	if _, socketActivated := os.LookupEnv("LISTEN_FDS"); socketActivated {
		listeners, err := activation.Listeners()
		if len(listeners) < 1 || err != nil {
			log.Fatalf("Socket activated, but without any listener. Err: %v", err)
		}
		ln = listeners[0]

		lingerCtx := idletracker.NewIdleTracker(ctx, 15*time.Minute)
		go func() {
			<-lingerCtx.Done():
			tearDownCtx, _ := context.WithTimeout(ctx, 10*time.Second)
			server.Shutdown(tearDownCtx)
		}()
		server.ConnState = lingerCtx.ConnState
	} else {
		listener, err := net.Listen("tcp", *httpAddr)
		if err != nil {
			log.Fatalf("net.Listen %s: %v", *httpAddr, err)
		}
		ln = listener
	}

	if err := server.Serve(ln); err != nil && err != http.ErrServerClosed {
		log.Fatalf("ListenAndServe %s: %v", *httpAddr, err)
	}
	cancelFn()
}

Documentation

Overview

Package idletracker contains a context that is done when a server has not had active (stream) connections for some time.

This can be used to stop idle services, and works well in conjunction with socket-activated daemons.

Example
package main

import (
	"context"
	"log"
	"net"
	"net/http"
	"time"

	"github.com/wmark/idletracker"
)

func main() {
	ctx, cancelFn := context.WithCancel(context.Background())
	lingerCtx := idletracker.NewIdleTracker(ctx, 15*time.Minute)

	server := &http.Server{
		IdleTimeout: 2 * time.Minute,
		ConnState:   lingerCtx.ConnState,
	}
	ln, _ := net.Listen("tcp", "[::1]:0")

	go func() {
		<-lingerCtx.Done()
		server.Shutdown(ctx)
	}()

	err := server.Serve(ln)
	if err != nil && err != http.ErrServerClosed {
		// …
		log.Fatalf("serve.Serve: %v\n", err)
	}
	cancelFn()
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type IdleTracker

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

IdleTracker maintains a list of dangling connections and a timer. It can be used in place of a Context with a deadline, to limit any residual work to the lifetime of the managed server.

func NewIdleTracker

func NewIdleTracker(parent context.Context, patience time.Duration) *IdleTracker

NewIdleTracker returns an instance with a running deadline timer. That is, even absent any original connection, the service will have a lifetime.

Don't reuse this as its assumption is that a server that has been torn down won't be revived.

func (*IdleTracker) ConnState

func (t *IdleTracker) ConnState(conn net.Conn, state http.ConnState)

ConnState implements the net/http.Server.ConnState interface.

func (*IdleTracker) Deadline

func (t *IdleTracker) Deadline() (deadline time.Time, ok bool)

Deadline implements the context.Context interface but breaks the promise of always returning the same deadline.

func (*IdleTracker) Done

func (t *IdleTracker) Done() <-chan struct{}

Done implements the context.Context interface.

func (*IdleTracker) Err

func (t *IdleTracker) Err() error

Err implements the context.Context interface.

func (*IdleTracker) String

func (*IdleTracker) String() string

String implements the fmt.Stringer interface.

func (*IdleTracker) Value

func (t *IdleTracker) Value(key interface{}) interface{}

Value implements the context.Context interface.

Jump to

Keyboard shortcuts

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