Go to file
Pavel Shevaev 850aafbacf First commit 2022-10-26 12:33:25 +03:00
.travis.yml First commit 2022-10-26 12:33:25 +03:00
LICENSE First commit 2022-10-26 12:33:25 +03:00
README.md First commit 2022-10-26 12:33:25 +03:00
child.go First commit 2022-10-26 12:33:25 +03:00
child_test.go First commit 2022-10-26 12:33:25 +03:00
doc.go First commit 2022-10-26 12:33:25 +03:00
dup_file.go First commit 2022-10-26 12:33:25 +03:00
dup_file_legacy.go First commit 2022-10-26 12:33:25 +03:00
env.go First commit 2022-10-26 12:33:25 +03:00
env_test.go First commit 2022-10-26 12:33:25 +03:00
fds.go First commit 2022-10-26 12:33:25 +03:00
fds_test.go First commit 2022-10-26 12:33:25 +03:00
go.mod First commit 2022-10-26 12:33:25 +03:00
go.sum First commit 2022-10-26 12:33:25 +03:00
http_example_test.go First commit 2022-10-26 12:33:25 +03:00
parent.go First commit 2022-10-26 12:33:25 +03:00
parent_test.go First commit 2022-10-26 12:33:25 +03:00
process.go First commit 2022-10-26 12:33:25 +03:00
process_test.go First commit 2022-10-26 12:33:25 +03:00
tcp_example_test.go First commit 2022-10-26 12:33:25 +03:00
upgrader.go First commit 2022-10-26 12:33:25 +03:00
upgrader_test.go First commit 2022-10-26 12:33:25 +03:00

README.md

Graceful process restarts in Go

It is sometimes useful to update the running code and / or configuration of a network service, without disrupting existing connections. Usually, this is achieved by starting a new process, somehow transferring clients to it and then exiting the old process.

There are many ways to implement graceful upgrades. They vary wildly in the trade-offs they make, and how much control they afford the user. This library has the following goals:

  • No old code keeps running after a successful upgrade
  • The new process has a grace period for performing initialisation
  • Crashing during initialisation is OK
  • Only a single upgrade is ever run in parallel

tableflip does not work on Windows.

It's easy to get started:

upg, err := tableflip.New(tableflip.Options{})
if err != nil {
	panic(err)
}
defer upg.Stop()

go func() {
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGHUP)
	for range sig {
		err := upg.Upgrade()
		if err != nil {
			log.Println("Upgrade failed:", err)
			continue
		}

		log.Println("Upgrade succeeded")
	}
}()

ln, err := upg.Fds.Listen("tcp", "localhost:8080")
if err != nil {
	log.Fatalln("Can't listen:", err)
}

var server http.Server
go server.Serve(ln)

if err := upg.Ready(); err != nil {
	panic(err)
}
<-upg.Exit()

time.AfterFunc(30*time.Second, func() {
	os.Exit(1)
})

_ = server.Shutdown(context.Background())