150 lines
3.2 KiB
Markdown
150 lines
3.2 KiB
Markdown
# 业务代码处理 SIGTERM 信号
|
|
|
|
要实现优雅终止,首先业务代码得支持下优雅终止的逻辑,在业务代码里面处理下 `SIGTERM` 信号,一般主要逻辑就是"排水",即等待存量的任务或连接完全结束,再退出进程。
|
|
|
|
本文给出各种语言的代码示例。
|
|
|
|
## shell
|
|
|
|
```bash
|
|
#!/bin/sh
|
|
|
|
## Redirecting Filehanders
|
|
ln -sf /proc/$$/fd/1 /log/stdout.log
|
|
ln -sf /proc/$$/fd/2 /log/stderr.log
|
|
|
|
## Pre execution handler
|
|
pre_execution_handler() {
|
|
## Pre Execution
|
|
# TODO: put your pre execution steps here
|
|
: # delete this nop
|
|
}
|
|
|
|
## Post execution handler
|
|
post_execution_handler() {
|
|
## Post Execution
|
|
# TODO: put your post execution steps here
|
|
: # delete this nop
|
|
}
|
|
|
|
## Sigterm Handler
|
|
sigterm_handler() {
|
|
if [ $pid -ne 0 ]; then
|
|
# the above if statement is important because it ensures
|
|
# that the application has already started. without it you
|
|
# could attempt cleanup steps if the application failed to
|
|
# start, causing errors.
|
|
kill -15 "$pid"
|
|
wait "$pid"
|
|
post_execution_handler
|
|
fi
|
|
exit 143; # 128 + 15 -- SIGTERM
|
|
}
|
|
|
|
## Setup signal trap
|
|
# on callback execute the specified handler
|
|
trap 'sigterm_handler' SIGTERM
|
|
|
|
## Initialization
|
|
pre_execution_handler
|
|
|
|
## Start Process
|
|
# run process in background and record PID
|
|
>/log/stdout.log 2>/log/stderr.log "$@" &
|
|
pid="$!"
|
|
# Application can log to stdout/stderr, /log/stdout.log or /log/stderr.log
|
|
|
|
## Wait forever until app dies
|
|
wait "$pid"
|
|
return_code="$?"
|
|
|
|
## Cleanup
|
|
post_execution_handler
|
|
# echo the return code of the application
|
|
exit $return_code
|
|
```
|
|
|
|
## Go
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
)
|
|
|
|
func main() {
|
|
|
|
sigs := make(chan os.Signal, 1)
|
|
done := make(chan bool, 1)
|
|
//registers the channel
|
|
signal.Notify(sigs, syscall.SIGTERM)
|
|
|
|
go func() {
|
|
sig := <-sigs
|
|
fmt.Println("Caught SIGTERM, shutting down")
|
|
// Finish any outstanding requests, then...
|
|
done <- true
|
|
}()
|
|
|
|
fmt.Println("Starting application")
|
|
// Main logic goes here
|
|
<-done
|
|
fmt.Println("exiting")
|
|
}
|
|
```
|
|
|
|
## Python
|
|
|
|
```python
|
|
import signal, time, os
|
|
|
|
def shutdown(signum, frame):
|
|
print('Caught SIGTERM, shutting down')
|
|
# Finish any outstanding requests, then...
|
|
exit(0)
|
|
|
|
if __name__ == '__main__':
|
|
# Register handler
|
|
signal.signal(signal.SIGTERM, shutdown)
|
|
# Main logic goes here
|
|
```
|
|
|
|
## NodeJS
|
|
|
|
```js
|
|
process.on('SIGTERM', () => {
|
|
console.log('The service is about to shut down!');
|
|
|
|
// Finish any outstanding requests, then...
|
|
process.exit(0);
|
|
});
|
|
```
|
|
|
|
## Java
|
|
|
|
```java
|
|
import sun.misc.Signal;
|
|
import sun.misc.SignalHandler;
|
|
|
|
public class ExampleSignalHandler {
|
|
public static void main(String... args) throws InterruptedException {
|
|
final long start = System.nanoTime();
|
|
Signal.handle(new Signal("TERM"), new SignalHandler() {
|
|
public void handle(Signal sig) {
|
|
System.out.format("\nProgram execution took %f seconds\n", (System.nanoTime() - start) / 1e9f);
|
|
System.exit(0);
|
|
}
|
|
});
|
|
int counter = 0;
|
|
while(true) {
|
|
System.out.println(counter++);
|
|
Thread.sleep(500);
|
|
}
|
|
}
|
|
}
|
|
```
|