Volt Introduction and Docs

Forking Server

development モードにおいて、Volt はアプリケーションのコードが変更された際にリロードする方法を必要とします。変更を検知するために、Volt は listen gem を使って、OS のファイル変更 API を利用し、変更に対してリッスンしています。development 環境、そして Linux または OS X で、かつ MRI を使用している場合は、Volt は ForkingServer としてアプリケーションを実行します。ForkingServer は Volt の Rack アプリケーションの背後で動作し、あらゆる Rack Web サーバー (thin、puma など) と一緒に動作することが可能です。

仕組み

Forking Server の背景となっているのは、アプリケーションに必要な依存関係にあるほとんどのもの (Ruby、Volt、Gem) をロードし、それから、分離した「子」プロセスにフォークする、という発想です。子プロセスの中で、アプリケーションのコードが読み込まれます。リクエストが親サーバーに届くと、それを子プロセスに (現在は DRb を利用して) 渡します。子プロセスはリクエストに対して返答し、その結果を親サーバーに返し、それが最終的にはブラウザーに送られます。

コードを変更した場合、その変更は親プロセスによって検知されます。もしその変更によってコードのリロードが必要であれば、親プロセスは子プロセスを kill します。それから、親プロセスは再度自分自身をフォークし、新しい子プロセスを生成します。それによって、アプリケーションのコードが再度ロードされます。

なぜ速いのか

アプリケーションのコードは、Ruby や Volt、そしてすべての依存関係にある Gem と比較すると小さいものなので、変更後のアプリケーションの起動は非常に高速です。「重たい」ところはすでにロード済みです。Linux と OS X はどちらも「コピーオンライト」のフォークをサポートしています。これは、プロセスのフォークの際に、元プロセスのメモリの完全なコピーを作るのではなく、メモリのブロックが変更されるまではコピーされないことを意味しています。アプリケーションコードのメモリの大部分は変更されないので、フォークは非常に高速に行えます。

利点

フォークによるリローディングが他の方法より優れている主な点は、コードのリロードによって失われるものがない点です。例えば Rails では、クラスは定数の定義を消すことによってアンロードされ、それから改めてファイルを require します。これが正しく動作するためには、require するファイルが、期待する命名規則にしたがっている必要があります。しかし、主な問題として、クラスの再読み込みが副作用を伴う、というものがあります。Ruby では、その副作用が目に見えないことも多いです (例えば、クラスの継承を行うと #inherited が呼び出されます) 。Forking Server を使うと、アプリケーションは、まるで0の状態から起動したときのように (ただし、その何分の1という時間で)、常に同じ状態になります。

他のプラットフォームやランタイム

ForkingServer の大きな制限は、フォークの存在しない Windows や Jruby では動作しないということです。Windows と Jruby をサポートするための代替のリローディング機構について計画中です。