risefront code.pfad.fr/risefront Index | Examples | Files

package risefront

import "code.pfad.fr/risefront"

package risefront enables gracefully upgrading the server behing a tcp connection with zero-downtime (without disturbing running transfers or dropping incoming requests).

Example (Http)

Code:

package main

import (
    "context"
    "errors"
    "net"
    "net/http"
    "os"
    "strconv"
    "time"

    "code.pfad.fr/risefront"
)

func newServer() *http.Server {
    // This is an example server, which shows the PID of its process.
    // Start processes in parallel to show the forwarding of the
    // incoming connection to the latest process.
    return &http.Server{
        Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            w.Write([]byte("hello world " + strconv.Itoa(os.Getpid()) + "\n"))
            if r.URL.Path == "/hang" {
                time.Sleep(10 * time.Second)
            }
            w.Write([]byte("bye " + strconv.Itoa(os.Getpid())))
        }),
    }
}

func main() {
    // In production, use signal.NotifyContext to interrupt on Ctrl+C:
    // ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()

    err := risefront.New(ctx, risefront.Config{
        Addresses: []string{":8080"},
        Run: func(l []net.Listener) error {
            // Example http.Server
            s := newServer()

            // defer Shutdown to wait for ongoing requests to be served before returning
            defer s.Shutdown(context.Background())
            return s.Serve(l[0]) // serve on the given listener
        },
    })
    if !errors.Is(err, context.DeadlineExceeded) {
        panic(err)
    }
}

Index

Examples

Package Files

firstchild_listener.go prefixDialer.go proxy.go risefront.go socket.go

func New

func New(ctx context.Context, cfg Config) error

New calls cfg.Run with opened listeners.

The parent will live as long as the context lives. The child will live as long as the parent is alive and no other child has been started.

type Config

type Config struct {
    Addresses []string                   // Addresses to listen to.
    Run       func([]net.Listener) error // Handle the connections. All open connections should be properly closed before returning (srv.Shutdown for http.Server for instance).

    Dialer       Dialer                       // Dialer for child-parent communication. Let empty for default dialer (PrefixDialer{}).
    Network      string                       // "tcp" (default if empty), "tcp4", "tcp6", "unix" or "unixpacket"
    ErrorHandler func(kind string, err error) // Where errors should be logged (print to stderr by default)
    // contains filtered or unexported fields
}

type Dialer

type Dialer interface {
    Listen(name string) (net.Listener, error)
    Dial(name string) (net.Conn, error)
}

Dialer is used for the child-parent communication.

type PrefixDialer

type PrefixDialer struct {
    Prefix string
}

PrefixDialer uses github.com/Microsoft/go-winio.{DialPipe,ListenPipe} on windows and net.{Dial,Listen} on other platforms.

func (PrefixDialer) Dial

func (pd PrefixDialer) Dial(name string) (net.Conn, error)

func (PrefixDialer) Listen

func (pd PrefixDialer) Listen(name string) (net.Listener, error)
Version
v1.0.0 (latest)
Published
Nov 25, 2022
Platform
linux/amd64
Imports
15 packages (graph)
Last checked
2 months ago

Tools for package owners.