jpillora / overseer

Monitorable, gracefully restarting, self-upgrading binaries in Go (golang)
MIT License
2.29k stars 208 forks source link

overseer

GoDoc Tests

overseer is a package for creating monitorable, gracefully restarting, self-upgrading binaries in Go (golang). The main goal of this project is to facilitate the creation of self-upgrading binaries which play nice with standard process managers, secondly it should expose a small and simple API with reasonable defaults.

overseer diagram

Commonly, graceful restarts are performed by the active process (dark blue) closing its listeners and passing these matching listening socket files (green) over to a newly started process. This restart causes any foreground process monitoring to incorrectly detect a program crash. overseer attempts to solve this by using a small process to perform this socket file exchange and proxying signals and exit code from the active process.

Features

Install

go get github.com/jpillora/overseer

Quick example

This program works with process managers, supports graceful, zero-down time restarts and self-upgrades its own binary.

package main

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

    "github.com/jpillora/overseer"
    "github.com/jpillora/overseer/fetcher"
)

//create another main() to run the overseer process
//and then convert your old main() into a 'prog(state)'
func main() {
    overseer.Run(overseer.Config{
        Program: prog,
        Address: ":3000",
        Fetcher: &fetcher.HTTP{
            URL:      "http://localhost:4000/binaries/myapp",
            Interval: 1 * time.Second,
        },
    })
}

//prog(state) runs in a child process
func prog(state overseer.State) {
    log.Printf("app (%s) listening...", state.ID)
    http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "app (%s) says hello\n", state.ID)
    }))
    http.Serve(state.Listener, nil)
}

How it works:

See Configuration options here and the runtime State available to your program here.

More examples

See the example/ directory and run example.sh, you should see the following output:

$ cd example/
$ sh example.sh
BUILT APP (1)
RUNNING APP
app#1 (c7940a5bfc3f0e8633d3bf775f54bb59f50b338e) listening...
app#1 (c7940a5bfc3f0e8633d3bf775f54bb59f50b338e) says hello
app#1 (c7940a5bfc3f0e8633d3bf775f54bb59f50b338e) says hello
BUILT APP (2)
app#2 (3dacb8bc673c1b4d38f8fb4fad5b017671aa8a67) listening...
app#2 (3dacb8bc673c1b4d38f8fb4fad5b017671aa8a67) says hello
app#2 (3dacb8bc673c1b4d38f8fb4fad5b017671aa8a67) says hello
app#1 (c7940a5bfc3f0e8633d3bf775f54bb59f50b338e) says hello
app#1 (c7940a5bfc3f0e8633d3bf775f54bb59f50b338e) exiting...
BUILT APP (3)
app#3 (b7614e7ff42eed8bb334ed35237743b0e4041678) listening...
app#3 (b7614e7ff42eed8bb334ed35237743b0e4041678) says hello
app#3 (b7614e7ff42eed8bb334ed35237743b0e4041678) says hello
app#2 (3dacb8bc673c1b4d38f8fb4fad5b017671aa8a67) says hello
app#2 (3dacb8bc673c1b4d38f8fb4fad5b017671aa8a67) exiting...
app#3 (b7614e7ff42eed8bb334ed35237743b0e4041678) says hello

Note: app#1 stays running until the last request is closed.

Only use graceful restarts

func main() {
    overseer.Run(overseer.Config{
        Program: prog,
        Address: ":3000",
    })
}

Send main a SIGUSR2 (Config.RestartSignal) to manually trigger a restart

Only use auto-upgrades, no restarts

func main() {
    overseer.Run(overseer.Config{
        Program: prog,
        NoRestart: true,
        Fetcher: &fetcher.HTTP{
            URL:      "http://localhost:4000/binaries/myapp",
            Interval: 1 * time.Second,
        },
    })
}

Your binary will be upgraded though it will require manual restart from the user, suitable for creating self-upgrading command-line applications.

Multi-platform binaries using a dynamic fetch URL

func main() {
    overseer.Run(overseer.Config{
        Program: prog,
        Fetcher: &fetcher.HTTP{
            URL: "http://localhost:4000/binaries/app-"+runtime.GOOS+"-"+runtime.GOARCH,
            //e.g.http://localhost:4000/binaries/app-linux-amd64
        },
    })
}

Known issues

More documentation

Third-party Fetchers

Contributing

See CONTRIBUTING.md