Graceful service shutdown
If your service maintains state such as a connection pool, a buffer, etc., you might want to close or flush it gracefully when the application exits.
When the do.Shutdown[type]()
or the injector.Shutdown()
function is called, the framework triggers the Shutdown
method of each service implementing the do.Shutdowner
interface, in reverse invocation order.
🛑 Services can be shut down properly, in reverse initialization order. Requesting a shutdown on a scope also shuts down its children recursively.
Trigger shutdown
A shutdown can be triggered on a root scope:
// on demand
injector.Shutdown() *do.ShutdownReport
injector.ShutdownWithContext(context.Context) *do.ShutdownReport
// on signal (helper methods on the root scope)
injector.ShutdownOnSignals(...os.Signal) (os.Signal, *do.ShutdownReport)
injector.ShutdownOnSignalsWithContext(context.Context, ...os.Signal) (os.Signal, *do.ShutdownReport)
...on a single service:
// returns error on failure
do.Shutdown[T any](do.Injector) error
do.ShutdownWithContext[T any](context.Context, do.Injector) error
do.ShutdownNamed(do.Injector, string) error
do.ShutdownNamedWithContext(context.Context, do.Injector, string) error
// panics on failure
do.MustShutdown[T any](do.Injector)
do.MustShutdownWithContext[T any](context.Context, do.Injector)
do.MustShutdownNamed(do.Injector, string)
do.MustShutdownNamedWithContext(context.Context, do.Injector, string)
If no signal is passed to injector.ShutdownOnSignals(...)
, both syscall.SIGTERM
and os.Interrupt
are handled by default.
Shutdowner interfaces
Your service can implement one of the following signatures:
type Shutdowner interface {
Shutdown()
}
type ShutdownerWithError interface {
Shutdown() error
}
type ShutdownerWithContext interface {
Shutdown(context.Context)
}
type ShutdownerWithContextAndError interface {
Shutdown(context.Context) error
}
Example:
// Ensure at compile-time MyService implements do.ShutdownerWithContextAndError
var _ do.ShutdownerWithContextAndError = (*MyService)(nil)
type MyService struct {}
func (*MyService) Shutdown(context.Context) error {
// ...
return nil
}
i := do.New()
Provide(i, ...)
Invoke(i, ...)
ctx := context.WithTimeout(10 * time.Second)
errors := i.ShutdownWithContext(ctx)
if err != nil {
log.Println("shutdown error:", err)
}