netutil

package module
v1.0.0 Latest Latest
Warning

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

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

README

netutil

PkgGoDev

IdleTracker: Close Idle Server Instances

When the http.Server you'd configure this with has not received new connections for some time, the context IdleTracker implements will be done, which can be used to initiate an orderly shutdown.

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

AcceptedConnection

Remember inetd or xinetd? Systemd can start server instances for every incoming connection, which AcceptedConnection upgrades to a net.Listener that you can pass to http.Server.

For whenever every process needs its own ephemeral environment, or any isolation from other instances. Like code runners, such as found in CI or Godoc's “playground”.

Documentation

Overview

Package netutil contains specialty network utilities for on-prem “cloud”-like services.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func AcceptedConnection

func AcceptedConnection(connection *os.File) (net.Listener, error)

AcceptedConnection wraps the connection as net.Listener.

This is meant for socekt activated services that get run for every incoming connection the caller (like systemd) has already accepted.

Unless the http.Server is meant to handle more than one request per connection, remember to have http.Server close it after the first, by setting this HTTP Header:

w.Header().Set("Connection", "close")

Passed to a http.Server, the latter will also return os.ErrClosed signalling its natural end (shutdown). Check for this wherever you expect http.ErrServerClosed to avoid that "false" error.

Example
package main

import (
	"log"
	"net"
	"net/http"
	"os"

	"github.com/coreos/go-systemd/v22/activation"
	netutil "github.com/wmark/go.netutil"
)

func main() {
	// Upgrades the connection to a net.Listener,
	// in case of socket- or connection-activated services.

	var ln net.Listener
	if _, acceptedConn := os.LookupEnv("LISTEN_FDS"); acceptedConn {
		fds := activation.Files(true) // Accept=true makes that connections.
		if len(fds) < 1 {
			log.Fatalf("Conn activated, but not been given any FD")
		}
		ln, _ = netutil.AcceptedConnection(fds[0])
	} else {
		// Traditional standalone invocation.
		ln, _ = net.Listen("tcp", "localhost:0")
	}

	server := &http.Server{}
	server.SetKeepAlivesEnabled(false)

	switch err := server.Serve(ln); err {
	case nil, http.ErrServerClosed, os.ErrClosed:
		return
	default:
		log.Fatalf("server.Serve: %v", err)
	}
}
Output:

Types

type IdleTracker

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

IdleTracker is done after no new connections happened for some time. This can be used to stop idle services.

It can be used in place of a context.WithDeadline to bind any lifetime/runtime of residual work to that of the server's.

Example
package main

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

	netutil "github.com/wmark/go.netutil"
)

func main() {
	// Stops the server after 15 minutes without any connection.

	ctx, cancelFn := context.WithCancel(context.Background())
	lingerCtx := netutil.NewIdleTracker(ctx, 15*time.Minute)

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

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

	_ = server.Serve(ln)
	cancelFn()
}
Output:

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