Ctrl+C in Go: Intercepting SIGINT and "defer" Cleanup Under the Hood

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Can you intercept Ctrl+C in Go and execute cleanup like defer? Under the hood analysis

\n\n

Have you ever started a server in Go, pressed Ctrl+C, and wondered: "What if, before exiting, I could neatly close database connections, save the cache, or just say 'Goodbye!'?" This question is so popular on Stack Overflow (thousands of views!) that we decided to break it down in detail. Today, we won't just give you a ready-made recipe; we'll look under the hood — how Go handles signals, what signal.Notify is, and why defer isn't quite the main player here.

\n\n

Ready? Let's go!

\n\n

The Problem: Ctrl+C kills the program instantly

\n\n

By default, when you press Ctrl+C in the terminal, the OS sends the SIGINT signal to the process. If the Go program does nothing, it terminates abruptly — all goroutines are cut off, and defer functions are not executed. It's like pulling the plug from the socket: the computer turns off, but data can be lost.

\n\n

A classic example: you're writing a web server, opening a connection to PostgreSQL, and suddenly — Ctrl+C. If the signal is not handled, the connection will hang, and the connection pool won't be released. After a few such restarts, the database will say: "Sorry, I can't take any more."

\n\n
package main\n\nimport (\n    "fmt"\n    "os"\n    "os/signal"\n    "syscall"\n)\n\nfunc main() {\n    // ... your code\n    fmt.Println("Press Ctrl+C to exit")\n    // Wait for signal\n    sig := make(chan os.Signal, 1)\n    signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)\n    <-sig\n    fmt.Println("Signal received, shutting down...")\n}
\n\n

This code already catches the signal, but what if we need to perform complex cleanup? That's where the magic begins.

\n\n

How it works under the hood: signal.Notify and channels

\n\n

The signal.Notify function registers your channel to receive specific signals. When the OS sends a signal, the Go runtime places it into the channel. If the channel is buffered (and we made a buffer of 1), the signal won't be lost, even if the receiving goroutine is busy.

\n\n

An important nuance: signal.Notify intercepts the signal but does not block its propagation. If you don't handle the signal in the channel, the program will still terminate after executing defer (if any exist in main). But if you want to perform cleanup, you need to wait for it to complete.

\n\n

Workflow diagram:

\n
    \n
  • OS → sends SIGINT to the process
  • \n
  • Go runtime → places the signal into the channel registered via signal.Notify
  • \n
  • Your goroutine → reads from the channel and starts cleanup
  • \n
  • After cleanup → you call os.Exit(0) or simply exit main
  • \n
\n\n

But how do you make cleanup "in the style of defer"? After all, defer executes when a function returns, not when a signal is received. The answer: use defer + blocking main until the signal is received.

\n\n

Recipe: "defer-like" cleanup on Ctrl+C

\n\n

The idea is simple: we write cleanup functions that should execute upon termination and "attach" them to defer. Then we block main until a signal is received. When the signal arrives, main terminates, and all defer functions run. Elegant, isn't it?

\n\n
package main\n\nimport (\n    "fmt"\n    "os"\n    "os/signal"\n    "syscall"\n    "time"\n)\n\nfunc cleanup() {\n    fmt.Println("Cleanup: closing connections...")\n    time.Sleep(2 * time.Second) // simulate work\n    fmt.Println("Cleanup complete")\n}\n\nfunc main() {\n    // defer will execute on any termination of main\n    defer cleanup()\n\n    // Channel for signal\n    sig := make(chan os.Signal, 1)\n    signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)\n\n    fmt.Println("Server started. Press Ctrl+C to stop.")\n    fmt.Println("Performing cleanup...")\n\n    //                

Blogs

Book Recommendations