読者です 読者をやめる 読者になる 読者になる

bekkou68の日記

開発しているサービス, IT技術, 英語など。

『Working with Unix Processes』の Appendix: How Unicorn Reaps Worker Processes を読みました

Unix Unicorn 勉強会

はじめに

How Resque Manages Processes の続きです。

主旨

Unicorn が親プロセスを終了する際に、どうやって親なし子プロセスができないように制御しているかを読み解く。

コードリーディング大会

勉強会メンバーでコードを読んでみました。読んだコードはこちら。コメントに理解や疑問などを書きました。

def stop(graceful = true)
  self.listeners = []
  limit = Time.now + timeout

  # なるべくワーカーが残らないように(関連※A)、
  # ワーカーが全て終了するかタイムアウトになるまで、
  # ワーカーを終了させる処理を続ける。
  until WORKERS.empty? || Time.now > limit
    kill_each_worker(graceful ? :QUIT : :TERM)
    sleep(0.1) # これはなんで必要なの?
    reap_all_workers
  end
  kill_each_worker(:KILL)
end
...
def reap_all_workers
  # 全てのワーカーが終了するまで終了処理を繰り返す
  begin
    # 任意の子プロセスをノンブロッキングで wait
    # *注意* 終了していない子プロセスが存在する場合は nil が返る
    wpid, status = Process.waitpid2(-1, Process::WNOHANG)
 
    # 子プロセスが無くなったら終了処理から抜ける。
    #
    # reap_all_workers を呼ぶ前にワーカーである子プロセス全てに QUITシグナルは
    # 送られている。そのため、子プロセスは終了しているはず。
    # だが、もし子プロセスが何らかの原因で終了していない場合は return される(関連※A)
    wpid or return
 
    if reexec_pid == wpid
      # ダウンタイム0 で再起動できる機能と関係のあるコード
      logger.error "reaped #{status.inspect} exec()-ed" self.reexec_pid = 0
      self.reexec_pid = 0
      self.pid = pid.chomp('.oldbin') if pid
      proc_name 'master'
    else
      # wait したワーカーを終了
      worker = WORKERS.delete(wpid) and worker.close rescue nil
 
      # ログ出力
      m = "reaped #{status.inspect} worker=#{worker.nr rescue 'unknown'}"
      status.success? ? logger.info(m) : logger.error(m)
    end
  rescue Errno::ECHILD
    # 子プロセスが存在しない場合=全てのワーカーが終了している場合
 
    break
  end while true
end
...
# 実行に長時間かかっているワーカーを終了する
def murder_lazy_workers
  ...
end

本文では reap_all_workers の解説がさらに詳しく書かれています。ぜひ読んでみてください。

感想

Unicorn を使って Gogengo! というサービスを動かしているのですが、Unicorn の仕組みを学んだのは初めてでした。とても面白かったです^^ reap_all_workersメソッド の挙動を読んだときに「子プロセスが QUITシグナルを送っても終了しなかった場合は残ってしまうのではないか?」という疑問がありました(本文には stopメソッドの解説はありませんでした)。stopメソッドを読んでみるとタイムアウトするまで reap_all_workers をリトライしていたので、残るのを防止しているのか、とわかりました。
本文を読むことで理解が深まり、疑問が出てきて、オープンソースを読み進めるとさらに理解が深まる。このような良い循環ができるのが本書の魅力の一つだと思います。勉強になる!

フレーズ

  • remiss without: これ無しには語れない
  • chock: つめ物
  • whet your appetite: 食欲をそそる
  • plumb the depth of: 〜の理解を深める
  • belly of the beast: 猛獣の巣窟。「不思議のダンジョン」シリーズでいうモンスターハウスみたなイメージだと思う