Module: CopyTunerClient::ForkHook
- Defined in:
- lib/copy_tuner_client/fork_hook.rb
Overview
fork をまたいで poller スレッドを引き継ぐためのフック。 Process._fork に prepend し、fork の直前に poller を協調的に停止して、 fork のあと親子それぞれで張り直す。
Class Method Summary collapse
-
.install ⇒ Object
Module#prepend は同じモジュールを二重に挿さないので、呼び出し側で登録済みかを見なくてよい.
-
.log_error(message) ⇒ Object
ログ出力自体が失敗しても fork は成立させる。ここで例外を漏らすと、失敗を握るために 置いた rescue が逆に fork を壊す.
-
.restart_poller(poller) ⇒ Object
Process.singleton_class に prepend されるため、インスタンスメソッドとして定義すると Process 自身にメソッドが生えてしまう。フックの補助はモジュール側の特異メソッドに置く.
Instance Method Summary collapse
Class Method Details
.install ⇒ Object
Module#prepend は同じモジュールを二重に挿さないので、呼び出し側で登録済みかを見なくてよい
7 8 9 |
# File 'lib/copy_tuner_client/fork_hook.rb', line 7 def self.install ::Process.singleton_class.prepend(self) end |
.log_error(message) ⇒ Object
ログ出力自体が失敗しても fork は成立させる。ここで例外を漏らすと、失敗を握るために 置いた rescue が逆に fork を壊す
47 48 49 50 51 |
# File 'lib/copy_tuner_client/fork_hook.rb', line 47 def self.log_error() CopyTunerClient.configuration&.logger&.error() rescue StandardError nil end |
.restart_poller(poller) ⇒ Object
Process.singleton_class に prepend されるため、インスタンスメソッドとして定義すると Process 自身にメソッドが生えてしまう。フックの補助はモジュール側の特異メソッドに置く
fork 後に例外を漏らすと「子プロセスは生成済みなのに親の fork が例外を投げる」状態になり、 呼び出し側が子の pid を受け取れなくなる。起動の失敗はログに落として fork は成立させる
39 40 41 42 43 |
# File 'lib/copy_tuner_client/fork_hook.rb', line 39 def self.restart_poller(poller) poller.start rescue StandardError => e log_error("CopyTuner: fork 後の poller 起動に失敗しました: #{e.class}: #{e.}") end |
Instance Method Details
#_fork ⇒ Object
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/copy_tuner_client/fork_hook.rb', line 11 def _fork # fork はアプリの任意のタイミングで起きる。Process._fork への prepend は外せないので、 # configure 前や configuration 差し替え中に NoMethodError でアプリの fork を # 壊さないよう nil を許容する poller = CopyTunerClient.configuration&.poller # スレッドは子プロセスに引き継がれない。fork 後に子へ残る Thread オブジェクトの見え方 # (alive? / join の結果)はドキュメント化されていない CRuby の実装依存なので、 # そこに依存した後始末はせず、fork 前に協調的に停止しておく。 # ここは rescue しない。停止の失敗を握り潰すと、動いている poller ごと fork することになり # このフックの目的そのものを裏切る restart = poller ? poller.stop : false begin super ensure # ensure は親(super の戻り値 = 子の pid)と子(同 0)の両方を通り、super が失敗した # ときも親で復元する。「fork 前に動いていたプロセスは fork 後も動いている」状態を保つ。 # 子でも張り直すのは、Puma の fork_worker のように worker が worker を fork する # 構成でもサーバ固有のフックに頼らず poller を立てるため ForkHook.restart_poller(poller) if restart end end |