{"id":37182720,"url":"https://github.com/hak5/overseer","last_synced_at":"2026-01-14T21:04:35.944Z","repository":{"id":57574019,"uuid":"263744463","full_name":"hak5/overseer","owner":"hak5","description":"Monitorable, gracefully restarting, self-upgrading binaries in Go (golang)","archived":false,"fork":true,"pushed_at":"2020-05-13T21:33:52.000Z","size":88,"stargazers_count":3,"open_issues_count":0,"forks_count":6,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-06-20T17:39:27.652Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"jpillora/overseer","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hak5.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-13T21:13:58.000Z","updated_at":"2023-07-25T14:35:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hak5/overseer","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/hak5/overseer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hak5%2Foverseer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hak5%2Foverseer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hak5%2Foverseer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hak5%2Foverseer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hak5","download_url":"https://codeload.github.com/hak5/overseer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hak5%2Foverseer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28434530,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T18:57:19.464Z","status":"ssl_error","status_checked_at":"2026-01-14T18:52:48.501Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-14T21:04:35.081Z","updated_at":"2026-01-14T21:04:35.936Z","avatar_url":"https://github.com/hak5.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# overseer\n\n[![GoDoc](https://godoc.org/github.com/jpillora/overseer?status.svg)](https://godoc.org/github.com/jpillora/overseer)\n\n`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.\n\n![overseer diagram](https://docs.google.com/drawings/d/1o12njYyRILy3UDs2E6JzyJEl0psU4ePYiMQ20jiuVOY/pub?w=566\u0026h=284)\n\nCommonly, 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.\n\n### Features\n\n* Simple\n* Works with process managers (systemd, upstart, supervisor, etc)\n* Graceful, zero-down time restarts\n* Easy self-upgrading binaries\n\n### Install\n\n```sh\ngo get github.com/jpillora/overseer\n```\n\n### Quick example\n\nThis program works with process managers, supports graceful, zero-down time restarts and self-upgrades its own binary.\n\n``` go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/jpillora/overseer\"\n\t\"github.com/jpillora/overseer/fetcher\"\n)\n\n//create another main() to run the overseer process\n//and then convert your old main() into a 'prog(state)'\nfunc main() {\n\toverseer.Run(overseer.Config{\n\t\tProgram: prog,\n\t\tAddress: \":3000\",\n\t\tFetcher: \u0026fetcher.HTTP{\n\t\t\tURL:      \"http://localhost:4000/binaries/myapp\",\n\t\t\tInterval: 1 * time.Second,\n\t\t},\n\t})\n}\n\n//prog(state) runs in a child process\nfunc prog(state overseer.State) {\n\tlog.Printf(\"app (%s) listening...\", state.ID)\n\thttp.Handle(\"/\", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tfmt.Fprintf(w, \"app (%s) says hello\\n\", state.ID)\n\t}))\n\thttp.Serve(state.Listener, nil)\n}\n```\n\n**How it works:**\n\n* `overseer` uses the main process to check for and install upgrades and a child process to run `Program`.\n* The main process retrieves the files of the listeners described by `Address/es`.\n* The child process is provided with these files which is converted into a `Listener/s` for the `Program` to consume.\n* All child process pipes are connected back to the main process.\n* All signals received on the main process are forwarded through to the child process.\n* `Fetcher` runs in a goroutine and checks for updates at preconfigured interval. When `Fetcher` returns a valid binary stream (`io.Reader`), the master process saves it to a temporary location, verifies it, replaces the current binary and initiates a graceful restart.\n* The `fetcher.HTTP` accepts a `URL`, it polls this URL with HEAD requests and until it detects a change. On change, we `GET` the `URL` and stream it back out to `overseer`. See also `fetcher.S3`.\n* Once a binary is received, it is run with a simple echo token to confirm it is a `overseer` binary.\n* Except for scheduled restarts, the active child process exiting will cause the main process to exit with the same code. So, **`overseer` is not a process manager**.\n\nSee [Config](https://godoc.org/github.com/jpillora/overseer#Config)uration options [here](https://godoc.org/github.com/jpillora/overseer#Config) and the runtime [State](https://godoc.org/github.com/jpillora/overseer#State) available to your program [here](https://godoc.org/github.com/jpillora/overseer#State).\n\n### More examples\n\nSee the [example/](example/) directory and run `example.sh`, you should see the following output:\n\n```sh\n$ cd example/\n$ sh example.sh\nBUILT APP (1)\nRUNNING APP\napp#1 (031c802ee74f00b2a5c52f2fe647523973c09441) listening...\napp#1 (031c802ee74f00b2a5c52f2fe647523973c09441) says hello\napp#1 (031c802ee74f00b2a5c52f2fe647523973c09441) says hello\nBUILT APP (2)\napp#2 (25d19f139f50f39fadbd066b438ebdc28d818eb1) listening...\napp#2 (25d19f139f50f39fadbd066b438ebdc28d818eb1) says hello\napp#2 (25d19f139f50f39fadbd066b438ebdc28d818eb1) says hello\napp#1 (031c802ee74f00b2a5c52f2fe647523973c09441) says hello\napp#1 (031c802ee74f00b2a5c52f2fe647523973c09441) exiting...\nBUILT APP (3)\napp#3 (5ed8170e5bbd6947cc514c87ac29e7acfba5cffc) listening...\napp#3 (5ed8170e5bbd6947cc514c87ac29e7acfba5cffc) says hello\napp#3 (5ed8170e5bbd6947cc514c87ac29e7acfba5cffc) says hello\napp#2 (25d19f139f50f39fadbd066b438ebdc28d818eb1) says hello\napp#2 (25d19f139f50f39fadbd066b438ebdc28d818eb1) exiting...\napp#3 (5ed8170e5bbd6947cc514c87ac29e7acfba5cffc) says hello\n```\n\n**Note:** `app#1` stays running until the last request is closed.\n\n#### Only use graceful restarts\n\n```go\nfunc main() {\n\toverseer.Run(overseer.Config{\n\t\tProgram: prog,\n\t\tAddress: \":3000\",\n\t})\n}\n```\n\nSend `main` a `SIGUSR2` (`Config.RestartSignal`) to manually trigger a restart\n\n#### Only use auto-upgrades, no restarts\n\n```go\nfunc main() {\n\toverseer.Run(overseer.Config{\n\t\tProgram: prog,\n\t\tNoRestart: true,\n\t\tFetcher: \u0026fetcher.HTTP{\n\t\t\tURL:      \"http://localhost:4000/binaries/myapp\",\n\t\t\tInterval: 1 * time.Second,\n\t\t},\n\t})\n}\n```\n\nYour binary will be upgraded though it will require manual restart from the user, suitable for creating self-upgrading command-line applications.\n\n#### Multi-platform binaries using a dynamic fetch `URL`\n\n```go\nfunc main() {\n\toverseer.Run(overseer.Config{\n\t\tProgram: prog,\n\t\tFetcher: \u0026fetcher.HTTP{\n\t\t\tURL: \"http://localhost:4000/binaries/app-\"+runtime.GOOS+\"-\"+runtime.GOARCH,\n\t\t\t//e.g.http://localhost:4000/binaries/app-linux-amd64\n\t\t},\n\t})\n}\n```\n\n### Known issues\n\n* The master process's `overseer.Config` cannot be changed via an upgrade, the master process must be restarted.\n\t* Therefore, `Addresses` can only be changed by restarting the main process.\n* Currently shells out to `mv` for moving files because `mv` handles cross-partition moves unlike `os.Rename`.\n* Only supported on darwin and linux.\n* Package `init()` functions will run twice on start, once in the main process and once in the child process.\n\n### More documentation\n\n* [Core `overseer` package](https://godoc.org/github.com/jpillora/overseer)\n* [Common `fetcher.Interface`](https://godoc.org/github.com/jpillora/overseer/fetcher#Interface)\n\t* [File fetcher](https://godoc.org/github.com/jpillora/overseer/fetcher#File)\n\t* [HTTP fetcher](https://godoc.org/github.com/jpillora/overseer/fetcher#HTTP)\n\t* [S3 fetcher](https://godoc.org/github.com/jpillora/overseer/fetcher#S3)\n\t* [Github fetcher](https://godoc.org/github.com/jpillora/overseer/fetcher#Github)\n\n### Third-party Fetchers\n\n* [overseer-bindiff](https://github.com/tgulacsi/overseer-bindiff) A binary diff fetcher and builder\n\n### Docker\n\n1. Compile your `overseer`able `app` to a `/path/on/docker/host/dir/app`\n1. Then run it with:\n\n\t```sh\n\t#run the app inside a standard Debian container\n\tdocker run -d -v /path/on/docker/host/dir/:/home/ -w /home/ debian /home/app\n\t```\n\n1. For testing, swap out `-d` (daemonize) for `--rm -it` (remove on exit, input, terminal)\n1. `app` should mount its parent directory as a volume in order to store the latest binaries on the host\n1. If the OS doesn't ship with TLS certs, you can mount them from the host with `-v /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt`\n\n### Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhak5%2Foverseer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhak5%2Foverseer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhak5%2Foverseer/lists"}