- Graceful Shutdown for your HTTP Server
- Graceful Shutdown for your Go Routines
- Middlewares for your Go Routines
- Cleanup after Shutdown
This package provides a method to gracefully shutdown your golang http server.
When a SIGTERM signal is received, the shutdown method on your server is executed. That means that no new connections are accepted but all running requests continue until finished.
func main() {
server := &http.Server{}
if err := graceful.ListenAndServe(server); err != nil && err != http.ErrServerClosed {
log.Println("Could not start server, error:", err.Error())
os.Exit(1)
}
}
After shutting down your server you can wait for registered go routines to finish before exiting.
func main() {
...
log.Println("Waiting for unfinished go routines...")
graceful.Wait() // blocks until all go routines are finished
}
To keep track of your started go routines you need to start them like this (otherwise you can't wait for them):
graceful.Run(func() {
// do not start a go routine on your own
// the go routine will be started in the package to keep track of it
})
It is possible to register middlewares that are applied automatically to all your go routines.
graceful.AddMiddleware(func(next func(context.Context)) func(context.Context) {
return func(ctx context.Context) {
// do something before your go routine
next(ctx)
// do something after your go routine
}
})
For middlewares to be useful you should provide a context that is passed down to your function. The context is also available in all middlewares.
graceful.RunContext(context.Background(), func(ctx context.Context) {
// do not start a go routine on your own
// the go routine will be started in the package to keep track of it
})
import (
"github.com/mattrx/graceful"
"go.opencensus.io/trace"
)
graceful.AddMiddleware(func(next func(context.Context)) func(context.Context) {
return func(ctx context.Context) {
ctx, span := trace.StartSpan(ctx, "go-routine")
defer span.End()
next(ctx)
}
})
import (
"github.com/mattrx/graceful"
)
graceful.AddMiddleware(func(next func(context.Context)) func(context.Context) {
return func(ctx context.Context) {
defer func() {
if err := recover(); err != nil {
// handle panic as you see fit
}
}()
next(ctx)
}
})
After shutting down you may want to run some cleanup functions to close connections or flush some internal memory buffer. You can run them like this:
func main() {
...
log.Println("Running cleanup functions...")
graceful.Cleanup()
}
In your code you just have to register the functions when you get them:
db, err := sqlx.Connect("mysql", config.FormatDSN())
...
graceful.AddCleanup(func() {
if err := db.Close(); err != nil {
log.Printf("Error closing db conn: %v", err)
}
})