Go言語でプロセスがKillされても正常な処理をしてから終了させる方法

Go言語

処理によっては、プロセスやサービスが停止する前に、データの整理や正常な終了手順の実行をしたい場合があります。
シグナルを使って、処理が強制終了されてもその前に、終了処理をする方法について解説をしていきます。

シグナルとは?

シグナルとはカーネルの機能で、プロセス間で通信を行う際に使用される信号のことで、シグナルを受け取ったプロセスは終了したり、再起動したりします。
シグナルにはいくつか種類があるのですが、今回関わるシグナルだけ下に上げておきます。動作に書いてあるTermというのは、シグナルの標準動作のことでプロセス終了を表します。

名前番号動作意味
SIGINT2Termキーボードからの割り込み(「CTRL」 + 「C」)
SIGKILL9Term強制終了シグナル(「kill -9」を実行)
SIGTERM15Term終了シグナル(オプションなしのkill)

実際にやったこと

SIGINTとSIGTERMのシグナルを受け取った時にだけ、後続処理を実行させて正常に完了するコードを書いてみました。

package main

import (
	"log"
	"os"
	"os/signal"
	"syscall"
)

func main() {
	waitSignal()
	log.Println("正常終了")
}

func waitSignal() {
	sig := make(chan os.Signal, 1)
	// 第2引数以降にハンドリングをしたいシグナルを設定する。
	// 設定したシグナル自体を受け取っても処理をしない
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
	// シグナルを受け取るまで待機
	<-sig
}

実行

実行して以下の3点を確認している。

  • CTRL + C で終了した時に「正常終了」が出力されるか
  • オプションなしのkillコマンドを実行して、「正常終了」が出力されるか
  • kill -9が実行されて、「正常終了」が出力されずに終了するか

# signalというファイル名を指定してgo build
signal % go build -o signal    
# CTRL + C で終了した時に「正常終了」が出力
signal % ./signal 
^C2024/03/06 09:45:03 正常終了
# killコマンドが実行されて、「正常終了」が出力(別ターミナルを開いてkillコマンドを実行)
signal % ./signal
2024/03/06 09:46:12 正常終了
# 強制終了のkillコマンドが実行されて、「正常終了」が出力されない(別ターミナルを開いてkill -9を実行)
signal % ./signal
zsh: killed     ./signal

これで設定されたシグナルでハンドリングができることを確認できました!!

参考

Linuxの「シグナル」って何だろう?
前回、ジョブを停止させる際に使用した[CTRL]+[Z]キーや、コマンドの実行を中断したいときの[CTRL]+[C]キーは、どんな意味を持つ操作なのでしょうか。今回は、Linuxの「プロセス」や「ジョブ」の制御に関わりの深い「シグナル」を解...

まとめ

今回はシグナルを使って、プロセスがkillされても正常な処理をしてから終了させる方法について解説をしてきました。他にもGo言語でjsonの処理や、Go言語で重要なcontextについて解説をしているいますので、そちらも見てもらえたらと思います。

【おすすめ記事のリンク】

コメント

タイトルとURLをコピーしました