Amblem
Furkan Baytekin

What Is a Graceful Shutdown?

Graceful shutdown implementation guide

What Is a Graceful Shutdown?
2
3 minutes

A graceful shutdown is the controlled process of stopping an application without interrupting active work. Instead of killing the process immediately, the system lets the application finish its ongoing tasks, close connections, and exit safely.


SIGTERM vs SIGKILL

These two signals behave differently:

SIGTERM

SIGKILL

A typical container lifecycle:

text
SIGTERM β†’ wait (10–30 seconds) β†’ SIGKILL

If the application doesn’t handle SIGTERM properly, it will be killed during the grace period and may lose data.


How a Graceful Shutdown Should Work

  1. Stop accepting new requests
  2. Stop background workers / cron jobs
  3. Stop queue consumers
  4. Finish active requests
  5. Close database pools
  6. Close Redis/caching connections
  7. Flush logs
  8. Exit before SIGKILL arrives

Graceful Shutdown in Node.js (Full Production Example)

Includes:

js
const http = require("http"); const { Pool } = require("pg"); const Redis = require("ioredis"); const cron = require("node-cron"); const db = new Pool({ connectionString: process.env.DB_URL }); const redis = new Redis(process.env.REDIS_URL); let isShuttingDown = false; const cronJob = cron.schedule("* * * * *", async () => { if (isShuttingDown) return; console.log("cron running..."); }); const server = http.createServer(async (req, res) => { if (isShuttingDown) { res.writeHead(503); // Service unavailable return res.end("Server shutting down"); } const value = await redis.get("counter"); res.end(`Counter: ${value}`); }); server.listen(3000, () => console.log("Server running on 3000")); async function gracefulShutdown() { if (isShuttingDown) return; isShuttingDown = true; console.log("Graceful shutdown started..."); cronJob.stop(); server.close(() => console.log("HTTP server closed")); try { await db.end(); console.log("DB closed"); } catch {} try { await redis.quit(); console.log("Redis closed"); } catch {} setTimeout(() => { console.log("Forced shutdown"); process.exit(1); }, 5000); } process.on("SIGTERM", gracefulShutdown); process.on("SIGINT", gracefulShutdown);

Graceful Shutdown in Go (Full Production Example)

Includes:

go
package main import ( "context" "log" "net/http" "os" "os/signal" "time" "github.com/go-redis/redis/v8" "github.com/jackc/pgx/v5/pgxpool" ) var ctx = context.Background() func main() { db, _ := pgxpool.New(ctx, os.Getenv("DB_URL")) redisClient := redis.NewClient(&redis.Options{ Addr: os.Getenv("REDIS_ADDR"), }) stopWorker := make(chan struct{}) go func() { ticker := time.NewTicker(1 * time.Minute) for { select { case <-ticker.C: log.Println("worker running...") case <-stopWorker: log.Println("worker stopped") return } } }() server := &http.Server{ Addr: ":8080", Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { val, _ := redisClient.Get(ctx, "counter").Result() w.Write([]byte(val)) }), } go func() { log.Println("Server running on 8080") server.ListenAndServe() }() sigs := make(chan os.Signal, 1) signal.Notify(sigs, os.Interrupt) <-sigs log.Println("Graceful shutdown started...") close(stopWorker) shutdownCtx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() server.Shutdown(shutdownCtx) db.Close() redisClient.Close() log.Println("Shutdown complete") }

Best Practices


Conclusion

A correct graceful shutdown protects application state, prevents data corruption, and ensures clean deploys. Handling SIGTERM properly and closing all critical resources is mandatory for production systems β€” especially in containerized environments.

If a version is needed specifically for Kubernetes, Docker Swarm, systemd services, or microservice architectures, it can be prepared as well.


Album of the blog:

Suggested Blog Posts