Yokohamaでついにお問い合わせ方法として「メッセージフォーム」が追加された。なにがついになのか、なにをドヤっているのかと思うかもしれない。ドヤってはいないのだが。実は私はかなり長い間ウェブアプリケーションをほとんど作っていない。今まで私が作ったウェブアプリケーションは、専用サーバーを持つサーブレットタイプか、もしくはCGIだった。馬鹿にされがちなCGIだが、利便性は高く、頻繁にアクセスする性質を持たないアプリケーションには適している。どちらかといえばウェブアプリケーションからは離れる方向にあった。ウェブアプリケーションを必要とするとしても大部分は静的ページとして提供できる方式を目指していたため、CGIで十分事足りたのである。ちなみに、これまでウェブサーバーはApachelighttpddelegateNginxという経過をたどっている。Apacheは言うに及ばずlighttpdとdelegateはApacheよりもCGIが簡単だったので、「ほぼCGI」だった。NginxはCGIをそもそもサポートしない。私も新しい時代に対応する必要がある。ちなみに、この作業は次の仕事のための実戦テストという意味合いもあった。NginxはFastCGIをサポートしている。FastCGIはプログラムをデーモンのように起動しっぱなしにする。通しで実行するプログラムとデーモンではそもそもの前提が違う。そのためCGIプログラムをFastCGIとして動かすのはそれなりにハードルが高い。Wrapの登場である。Wrapにする方式だ。このラッパープログラムは要求に合わせて都度CGIプログラムをCGIインターフェイス経由で起動する。結果的にFastCGIの意図は無視して従来型CGIを動作させるようにするというものだ。この方法は結構出てくるのだが、基本的には既存のCGIプログラムを動作させる話である。個人的な感覚としては、無駄なプロキシを噛ませるような方法を使ってまでCGIに固執したくない...というか、実はfcgi-wrapってそれなりにめんどくさい。FastCGI直というのもありかなぁ、と考えるわけだ。ところが、やっぱりFastCGIはデーモン状のプログラムを想定しているわけで、やはり前提が違う。要求として割と複雑なのか、デーモン化に関してはspawn-fcgiに担ってもらって、さらにRackを使う、というのがどうやら主流らしい。話が複雑になってきた。サーバーはNginxである。NginxはFastCGIインターフェイスを経由してFastCGIプログラムにパラメータを渡し、応答を受け取る。FastCGIプログラムはデーモンである。Rubyでは次のようにしてFastCGIプログラムを書くことができる。request.finish}あるいは、CGIライブラリ互換インターフェイスを使うことで、#each_cgiの中身はまるっきりCGIと同じにすることもできる。#{cgi.remote_addr}"}spawn-fcgiはこのデーモン部分を担う。eachしてる部分を担ってくれるわけだ。プロセスとしてCGIインターフェイスで起動するわけではないので、fcgiwrapほどの互換性はない。感覚はCGIに近いが、インターフェイスは意識する必要がある。Rackはミドルウェアと呼ばれている。これはまずFastCGI抜きで話そう。Rackはインターフェイスを担っている。今までプログラムはCGIなり、あるいはFCGIなり、さらには各種フレームワークやサーブレットの様式(例えばSinatraとか)で書いていた。Rackはこれらの違いを吸収するモジュール設計のものだ。Rackに準拠したプログラムを書いておけば、たとえ愛用のフレームワークがディスコンになっても、サーバーが変わっても安心、というわけだ。Rack自身はサーバーではないからサーバーがいるのだが、Rack組み込みのサーバーというのはもう完全にRuby世界の住人だ。RackはRubyのWebアプリケーションインターフェイスだから。Passengerというソフトウェアがあって、これはwebサーバーのモジュールとしてRackに対応する。Apacheでは比較的簡単だけれど、Nginxだと結構きつい。そこでRackに対応したサーバーを立ててサーバーとサーバーでやりとりさせる、という方式がすごく現代的。直接にRack経由でプログラムとやりとりするのはRackに対応したサーバーだけれど、Rackに対応したサーバーにwebサーバーとしての機能を持たせると大変なので、「本物のwebサーバーに矢面に立ってもらって、RackサーバーはあくまでRack対応に特化」というわけである。Unicornあたりがある。Rackという方法もある。それはRack側でFastCGI経由で受け取って、応答するためのハンドラが用意されている。Unicornのようなサーバーを立てる代わりの手段としてFastCGIが使える。FastCGIもデーモンを必要とするので別にFastCGIにすることで間に挟まってるものを減らす効果はない。話が楽になるだけである。Unicornはむちゃくちゃ速いので、UnicornでUnixドメインソケットを使えば形式とししてはspawn-fcgiでUnixドメインソケットを使っているのと一緒だし、やっていることははるかに高度になる。これが超モダンなやり方である。理由は管理する要素数を減らすためである。必要がないのにいかついものを使うことはしない。これはサーバー運用のコツでもある。Rackに関してはかなり情報が少ない。なんらかのフレームワーク...というか、ほぼRailsのバックエンドとしてのRackの話だけで、Rack単独の話ってない。FastCGIを使う話もない。これもだいたいなんらかのアプリケーションが「使ってる」あるいは「使わせる」話になる。世の中エンジニアたくさんいるのに、WordPressとRailsだけで満足なのか...そんなわけで情報が猛烈に足りていない中、FastCGIとRackについて勉強することになったわけだ。Nginxでアプリケーションとやりとりする方法に関してはDiscourceで散々やったので経験済みだ。RackなのかもちろんこのことからもわかるようにRackはなくても構わない。spawn-cgiも使用せず単独のFastCGIアプリケーションを開発するのは容易である。私が気にしたのはRubyのfcgiライブラリは2013年から更新が止まっているとい点だ。fcgiとするよりない。ベーシックな機構であるFastCGIそのものが廃止になるようなことは考えにくいが、NginxのCGIの扱いのように消極的なサポートへと変遷する可能性はある。その場合にアプリケーションの書き直しが発生してしまう。Rackは現在主流であり、新規採用例も多い。Rackが廃止になると影響を受ける範囲も非常に広いので今後10年は安泰だと思われる。そこでFastCGI+Rackという構成にしたわけだ。この場合でもRackはFastCGIをネイティブサポートしているわけではく、fcgiライブラリを使ったハンドラを同梱しているだけなのでfcgiライブラリは必要となる。実はこれを回避したかったのだが、結局はできなかった形だ。いえ、この状態であればFastCGIを捨ててUnicornに移行するのも難しくはない。Responseは単純に#finishでRackに沿った配列を返すための便利クラス。/var/www/testapp/testapp.rbforkingなので停止・再起動の制御のためPIDファイルを作る。multi-user.targetforkingなので$MAINPIDがそのままでは使えないため、PIDFileで指定しておく。Nginxのあとに起動しておいたほうがいいような気がしたけど、なくても構わない。アクセスが激しい場合は逆にNginxの前に起動したほうがいいだろうspawn-fcgi自体にはアプリをリロード、再起動するような機能はない。おまけS-NailがSubjectも本文も、UTF-8をちゃんとエンコードしてくれるのですごくびっくりした。「mailxとは違うのだよ!!!」ってことか。SMTPやPOPやIMAPにも対応しているだけのことはある。ここの部分(MIMEエンコーディング)も自分でやるつもりだったので、かなり省力化された形。今回の構築は他にも色々やったのだけれど、共有して意味のある部分はこれくらいのものだろう。