Graceful Shutdown Library for Go (G.S): Design, Usage, and Code Walkthrough
This article introduces the Go‑based G.S library for graceful application shutdown, analyzes common container‑related pitfalls, explains its lightweight architecture with TerminateSignal and WaitingUnit modules, provides installation steps, a complete usage example, and detailed code explanations to help developers implement reliable signal handling.
Graceful Shutdown Library for Go (G.S)
Author Lee, a veteran with 17 years in IT, observes that many projects nearing release suffer from poor container‑design practices, such as ignoring proper signal handling (SIGINT/SIGTERM/SIGQUIT) and lacking unified standards, which leads to unstable pod restarts and scaling.
Pain‑point Analysis
Insufficient awareness of container design principles
Developers often overlook container design guidelines.
Container issues are mistakenly treated as operations‑only problems.
Oversimplified coding attitude
Some believe container functionality is trivial and avoid writing robust code.
This leads to accepting any code that merely runs, regardless of quality.
Lack of unified standards affecting code reuse
Without common standards, developers implement features independently.
Resulting code is hard to reuse across projects.
The author extracted, refactored, and open‑sourced a solution to address these widespread issues.
Introduction
G.S– https://github.com/shengyanli1982/gs
G.S is a Go library that provides an easy way to achieve graceful shutdown of applications, supporting multiple signals, various shutdown methods, concurrent object termination, and customizable timeout handling. It has been used in production for over two years.
Architecture Design
The library consists of two modules:
TerminateSignal WaitingUnitIts core principles are "lightweight, easy‑to‑use, fast".
Module Overview
1. TerminateSignal
TerminateSignalis a struct that registers callbacks to be executed when a termination signal arrives. It supports a timeout mechanism and can accept an external context.Context to synchronize with other logic.
Key methods: CancelCallbacksRegistry(...func()) – registers callbacks for cancellation. GetStopCtx() – returns the context associated with the stop signal. Close(wg *sync.WaitGroup) – executes all registered callbacks, sends the shutdown signal, and waits for completion.
2. WaitingUnit
WaitingUnitblocks until all termination signals have finished executing their callbacks. It listens for SIGINT, SIGTERM, and SIGQUIT, making it an event‑driven design.
A single WaitingUnit can control multiple TerminateSignal instances, enabling coordinated graceful shutdown of many resources.
Installation
go get github.com/shengyanli1982/gsUsage Example
The following example demonstrates how to use G.S with three simulated services, each exposing a different shutdown method.
package main
import (
"fmt"
"os"
"time"
"github.com/shengyanli1982/gs"
)
// simulate a service
type testTerminateSignal struct{}
func (t *testTerminateSignal) Close() { fmt.Println("testTerminateSignal.Close()") }
// simulate another service
type testTerminateSignal2 struct{}
func (t *testTerminateSignal2) Shutdown() { fmt.Println("testTerminateSignal2.Shutdown()") }
// simulate a third service
type testTerminateSignal3 struct{}
func (t *testTerminateSignal3) Terminate() { fmt.Println("testTerminateSignal3.Terminate()") }
func main() {
// Create TerminateSignal instance
s := gs.NewDefaultTerminateSignal()
// Resources to be closed on termination
t1 := &testTerminateSignal{}
t2 := &testTerminateSignal2{}
t3 := &testTerminateSignal3{}
// Register their shutdown methods
s.CancelCallbacksRegistry(t1.Close, t2.Shutdown, t3.Terminate)
// Send an interrupt signal after 2 seconds
go func() {
time.Sleep(2 * time.Second)
p, err := os.FindProcess(os.Getpid())
if err != nil { fmt.Println(err.Error()) }
err = p.Signal(os.Interrupt)
if err != nil { fmt.Println(err.Error()) }
}()
// Wait for graceful shutdown
gs.WaitingForGracefulShutdown(s)
fmt.Println("shutdown gracefully")
}Running the program produces:
# go run main.go
testTerminateSignal3.Terminate()
testTerminateSignal.Close()
testTerminateSignal2.Shutdown()
shutdown gracefullyCode Analysis
The project mainly consists of two files: terminal.go and gracefull.go. Key excerpts are shown below.
terminal.go – TerminateSignal implementation
// Register callbacks to be canceled
func (s *TerminateSignal) CancelCallbacksRegistry(callbacks ...func()) {
s.exec = append(s.exec, callbacks...)
}
// Get the stop signal's Context
func (s *TerminateSignal) GetStopCtx() context.Context { return s.ctx }
// Close the TerminateSignal instance
func (s *TerminateSignal) Close(wg *sync.WaitGroup) {
s.once.Do(func() {
for _, cb := range s.exec {
if cb != nil {
s.wg.Add(1)
go s.worker(cb)
}
}
s.cancel()
s.wg.Wait()
if wg != nil { wg.Done() }
})
}
func (s *TerminateSignal) worker(callback func()) {
defer s.wg.Done()
<-s.ctx.Done()
callback()
}gracefull.go – WaitingUnit implementation
// Wait for all shutdown signals
func WaitingForGracefulShutdown(sigs ...*TerminateSignal) {
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
<-quit
signal.Stop(quit)
close(quit)
if len(sigs) > 0 {
var wg sync.WaitGroup
wg.Add(len(sigs))
for _, s := range sigs {
go s.Close(&wg)
}
wg.Wait()
}
}The WaitingForGracefulShutdown function blocks until a termination signal is received, then triggers all registered callbacks via the associated TerminateSignal instances.
Conclusion
By designing and implementing the G.S library, the author provides a minimal‑cost solution for graceful shutdown that can be reused across multiple services without extensive code changes. The library demonstrates a practical approach to reliable signal handling in Go backend applications, and the author invites feedback and contributions.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
