AWS ECSの停止の挙動
ECSは以下の順序でタスクを終了する。
- コンテナで動作しているプロセスにSIGTERMを送信する。
- 30秒待つ。
- プロセスが停止していなかったらSIGKILLを送信する。
この挙動は変更できないらしい。SIGKILLを送信するまでの秒数を長くしたりはできない。
停止処理をshellで雑に書く
shell scriptで記述するとこのようになる。
TARGET_PID=
kill -TERM $TARGET_PID
sleep 30
kill -KILL $TARGET_PID
今回はEmacs上からこのような処理をさせる実装を行う。
Emacsでプロセスを停止させる関数
Emacsでプロセスを停止させる関数はいくつかある。
- delete-process
- kill-process
- stop-process
- process-send-eof
- signal-process
今回はシグナルを指定して送信した処理にしたいので signal-process
を利用する。
プロセスのリストを取得する
process-list
関数はプロセスのリストを返す。
(process-list)
中身を確認すると実際にprocessのlistであることがわかる。
(type-of (car (process-list)))
process
プロセスをinteractiveで選択する
ミニバッファで一覧から選択させる場合 completing-read
関数を使う。
https://www.gnu.org/software/emacs/manual/html_node/elisp/Minibuffer-Completion.html
(defun example (procname)
(interactive (list
(completing-read "Process: " (mapcar #'process-name (process-list)))))
(print (get-process procname)))
プロセスにシグナルを送信する
list-processesのtabulated-modeから停止できるように拡張していく。
PSIXシグナル
今回はSIGTERMとSIGKILLを使用する。
シグナル | 番号 |
---|---|
SIGTERM | 15 |
SIGKILL | 9 |
Emacsでそれぞれのシグナルを表すシンボルは用意されていないが数字よりも シグナル名で記述できたほうがわかりやすくなるため定義しておく。
(setq
SIGKILL 9
SIGTERM 15)
使うものだけを定義した。
https://linuxjm.osdn.jp/html/LDP_man-pages/man7/signal.7.html
シグナルを送信する
(signal-process proc signal)
実行中のプロセスにシグナルを送信する
実行中のプロセスにシグナルを送信する関数を書くと次のようになる。
(defun process-graceful-shutdown-send-signal-running-process (proc signal-number)
"実行中のプロセスにシグナルを送信する。"
(when (eq (process-status proc) 'run)
(signal-process proc signal-number)))
タイマーを利用して30秒後にSIGKILLを送信する
30秒後にSIGKILLを送信する処理を行うためタイマーを利用する。プロセスが 生存していればSIGKILLを送信し、生存していなければ何もしない関数を作成 する。
list-processesのプロセス一覧からポイントしているプロセスを取得する
list-processesで表示されるプロセス一覧はtabulated-list-modeで実装されている。
カレントバッファがtabulated-list-modeの場合 tabulated-list-get-id
関数でidを取得できる。
プロセス一覧のバッファの場合、idはプロセス名になっている。
つまり以下のようなlispでプロセス自体を取得できる。
(get-process (tabulated-list-get-id))
ちなみにtabulated-list-modeではない場合 (tabulated-list-get-id)
を評価するとnilを返す。
今回はminiバッファでの選択時のデフォルト値にそれを設定したい。
completing-read
関数は引数でデフォルト値をするようにし、コマンドとして呼び出す関数 process-graceful-shutdown
を実装した。
(defun process-graceful-shutdown (proc)
"Graceful shutdownする。"
(interactive (list
(completing-read "Process: " (mapcar #'process-name (process-list))
nil nil nil nil (tabulated-list-get-id))))
(process-graceful-shutdown-send-signal-running-process proc SIGTERM)
(run-at-time 30 nil #'process-graceful-shutdown-send-signal-running-process proc SIGKILL))
最終的な実装
最終的に以下のような実装になった。
(setq
SIGKILL 9
SIGTERM 15)
(defun process-graceful-shutdown-send-signal-running-process (proc signal)
"実行中のプロセスにシグナルを送信する。"
(when (eq (process-status proc) 'run)
(signal-process proc signal)))
(defun process-graceful-shutdown (proc)
"Graceful shutdownする。"
(interactive (list
(completing-read "Process: " (mapcar #'process-name (process-list))
nil nil nil nil (tabulated-list-get-id))))
(process-graceful-shutdown-send-signal-running-process proc SIGTERM)
(run-at-time 30 nil #'process-graceful-shutdown-send-signal-running-process proc SIGKILL))
複雑なことはしてないのでシンプルな実装になった。
パッケージ化するほどのものでもないのでinit.elにでも書いてしまうことにする。
参考
- http://akisute3.hatenablog.com/entry/20111129/1322557154
- http://mukaer.com/archives/2012/03/24/emacsinteractiv/
- http://quruli.ivory.ne.jp/document/elisp_20.3/elisp_21.html#Prefix-Command-Arguments
- http://quruli.ivory.ne.jp/document/elisp_20.3/elisp_37.html
- https://ayatakesi.github.io/emacs/24.5/elisp_html/Running-Hooks.html
- https://ayatakesi.github.io/lispref/24.5/html/Timers.html#Timers
- https://blog.kyanny.me/entry/2015/12/28/220905
- https://flex.phys.tohoku.ac.jp/texi/eljman/eljman_104.html
- https://flex.phys.tohoku.ac.jp/texi/eljman/eljman_135.html
- https://linuxjm.osdn.jp/html/LDP_man-pages/man7/signal.7.html
- https://qiita.com/suin/items/122946f7d0cd13b143f9
- https://www.gnu.org/software/emacs/manual/html_node/elisp/Minibuffer-Completion.html
- https://www.gnu.org/software/emacs/manual/html_node/elisp/Process-Information.html
- https://www.gnu.org/software/emacs/manual/html_node/emacs/Hooks.html