From f88edf082e02fe26a8ada8b7b694192b70d976b6 Mon Sep 17 00:00:00 2001 From: Maxime Delporte Date: Wed, 19 Nov 2025 14:39:15 +0100 Subject: [PATCH] Adding 'Sending Shutdown Signals' section. --- README.md | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/README.md b/README.md index de46436..59ff42e 100644 --- a/README.md +++ b/README.md @@ -396,6 +396,72 @@ So, to get around this, we'll need to synchronize access to the map of rate limi If you're using HAProxy or Nginx as a load balancer or reverse proxy, both of these have built-in functionality for rate limiting that it would probably be sensible to use. Alternatively, you could use a fast database like Redis to maintain a request count for clients, running on a server which all your application servers can communicate with. +### Sending Shutdown Signals + +When our application is running, we can terminate it at any time by sending it a specific signal. A common way to do this, which you've probably been using, is by pressing **Ctrl+C** on your keyboard to send an interrupt signal - also known as a **SIGINT**. + +But this isn't the only type of signal which can stop our application. Some of the other common ones are: + +| Signal | Description | Keyboard shortcut | Catchable | +|---------|--------------------------------------|-------------------|-----------| +| SIGINT | Interrupt from keyboard | Ctrl + C | Yes | +| SIGQUIT | Quit from keyboard | Ctrl + C | Yes | +| SIGKILL | Kill process (terminate immediately) | - | No | +| SIGTERM | Terminate process in orderly manner | - | Yes | + +It's important to explain upfront that some signals are _catchable_ and others are not. Catchable signals can be intercepted by our application and either ignored, or used to trigger a certain action (such as a graceful shutdown). Other signals, like **SIGKILL**, are not catchable and cannot be intercepted. + +Let's take a quick look at these signals in action. First, run : + +```bash +$ go run ./cmd/api +time=2023-09-10T10:59:13.722+02:00 level=INFO msg="database connection pool established" +time=2023-09-10T10:59:13.722+02:00 level=INFO msg="starting server" addr=:4000 env=development +``` + +Doing this should start a process with the name **api** on your machine. You can use the pgrep command to verify that this process exists, like so: + +```bash +$ pgrep -l api +4414 api +``` + +In my case, I can see that the **api** process is running and has the _process ID_ **4414** (your process ID will most likely be different). + +Once that's confirmed, go ahead and try sending a **SIGKILL** signal to the **api** process using the pkill command like so: + +```bash +$ pkill -SIGKILL api +``` + +If you go back to the terminal window that is running the API application, you should see that it has been terminated and the final line in the output stream is **signal: killed**. Similar to this : + +```bash +$ go run ./cmd/api +time=2023-09-10T10:59:13.722+02:00 level=INFO msg="database connection pool established" +time=2023-09-10T10:59:13.722+02:00 level=INFO msg="starting server" addr=:4000 env=development +signal: killed +``` + +Feel free to repeat the same process, but sending a SIGTERM signal instead: + +```bash +$ pkill -SIGTERM api +``` + +This time, you should see the line **signal: terminated** at the end of the output, like so : + +```bash +$ go run ./cmd/api +time=2023-09-10T10:59:13.722+02:00 level=INFO msg="database connection pool established" +time=2023-09-10T10:59:13.722+02:00 level=INFO msg="starting server" addr=:4000 env=development +signal: terminated +``` +You can also try sending a **SIGQUIT** signal — either by pressing **Ctrl+\\** on your keyboard or running **pkill -SIGQUIT api**. This will cause the application to exit with a stack dump. + +We can see that these signals are effective in terminating our application - but the **problem** we have is that they all cause our application to **exit immediately**. + + ### Performance **json.MarshalIndent()** takes 65% longer to run and uses around 30% more memory than **json.Marshal()**, as well as making two more heap allocations. Those figures will change depending on what you're encoding, but they're fairly indicative of the performance impact.