Capistranoでバックグラウンドジョブを実行させたいときがある.
監視スクリプトなんかがいい例だ.
そんな時,2タイプの記事を見つけた.
sleep
すればいいよ
$ /dev/null
リダイレクト
どちらも正しいのだけれど,おそらく両方が成功するわけではない.
というのも,これは別の設定に依存している.
ptyという設定
Capistranoのはptyというオプションがある.
set :pty, true
このオプション,デフォルトではfalse
になっているが,結構true
にする記事も見かける.
そう,ptyとは仮想端末の割り当てフラグなのだ.
sudo
などはわかりやすい例で,やってみればわかるとは思うが,sshでコマンド引数からsudo
を実行する際などに必要になる.
仮想端末があるかないかによって変わる
例えば,& /dev/null
という設定はコマンドラインでよく見かけるバックグラウンドジョブの起動方法だ.
これがきっちりバックグラウンドに移るのかどうかについては,以下の記事が非常に詳しい.
技術/UNIX/なぜnohupをバックグランドジョブとして起動するのが定番なのか?(擬似端末, Pseudo Terminal, SIGHUP他) - Glamenv-Septzen.net
おそらくこの場合,ptyで割り当てられた仮想端末が終了するときに,同時にプロセスを殺してしまっている.これは,プロセスが「STOP状態 + J_NOHUP有」になるからだ.そのために仮想端末がSIGCONTを送信してしまっている.
では,sleep
は仮想端末が死んだ時,どうなるのか.
これは,sleep
が付くことにより,プロセスがrunning
状態になる.
これにより,上記記事の「RUNNING状態 + J_NOHUP無 」に該当し,SIGCONTとSIGTERMが送信されなくなる.そのため,プロセスは生き残る.
しかし,仮想端末がない状態でsleep
しても,単にCapistranoの実行が待たされるだけで,別にバックグラウンドに移るわけではないので,次の瞬間にはプロセスが殺されてしまう.
どうすればいいの?
ptyがtrue
のときはsleep
で
仮想端末がある場合は,上記の通り,sleep
で対応する.
set :pty, true namespace :deploy do task :hoge do run "(cd $DIR && (nohup sh ./background_script.sh &)) && sleep 1" end end
ptyがfalse
のときは& /dev/null
で
仮想端末がない場合は,通常のコマンドライン上でのバックグラウンド処理と同様になる.
set :pty, false namespace :deploy do task :hoge do run "sh -c 'cd $DIR && nohup sh ./background_script.sh &' >& /dev/null" end end