risefront package

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)
package main

import (


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) {



func New

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 Dialer

Dialer is used for the child-parent communication.

type PrefixDialer

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

func (PrefixDialer) Dial

func (PrefixDialer) Listen

Source Files

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



git clone