非同期HTTPクライアントem-http-requestを用いて複数のサーバーに同時リクエストできることを確認します。
クライアント
require 'eventmachine'
require 'em-http'
# ホスト:ポート生成
def host(i)
"http://localhost:#{9292 + i}/"
end
EM.run do
# 3つのリクエストを作成。
# localhostのポート9292, 9293, 9294で複数のサーバーが動いていることを想定。
# durationというパラメータ(後述)に適当な整数を渡している。
requests = Array.new(3) do |i|
EM::HttpRequest.new(host(i)).get :query => {'duration' => (3 + i)}
end
# 非同期リクエストのコールバック登録
requests.each do |request|
request.callback do
puts request.response
end
request.errback do
puts "Error: #{request.error}"
end
end
end
ダミーサーバー
寝るだけのRackアプリケーション
整数パラメータduration
に指定された秒数だけ寝た後で適当なJSONを返す簡単なRackアプリケーションを作ります。
require 'rack/response'
require 'json'
class Sleeper
def call(env)
req = Rack::Request.new(env)
t = req["duration"].to_i
puts "Going to sleep for #{t} seconds..."
sleep t
Rack::Response.new.finish do |res|
j = {pid: $$, duration: t}.to_json
res.write j
end
end
end
run Sleeper.new
WEBrickサーバー起動
上記Rackアプリケーションを実行します。コマンドラインから整数引数を受け取り、ポート番号に加え、RackアプリケーションをWEBrickサーバー上で実行します。ポート番号を可変にしているのは後でこのサーバーを別々のポートで複数起動するためです。
(走りっぱなしでkillし忘れるのが嫌なのでEM.defer
を使用して30秒後に自分自身にSIGINTを送信しています。Rack::Server
ではtrap(:INT)
でサーバーをshutdown
しています。)
require 'rack'
require 'eventmachine'
EM.run do
# 30秒後に終了。
EM.defer do
sleep 30
puts "Stopping server ..."
Process.kill :INT, $$
end
puts "Starting server ..."
# 上記のsleeper.ruを指定してサーバー開始。
Rack::Server.start server: "webrick", Port: (9292 + ARGV[0].to_i), config: "sleeper.ru"
puts "Bye."
EM.stop
end
動作確認
下記動作確認はMac OS Xで行っていますが、Linuxでも同様のはずです。
shellはbashを想定しています。
ダミーサーバー起動
# ポート9292, 9293, 9294でサーバーをバックグラウンド実行。
for i in `seq 0 2`
do
ruby spawn_sleeper.rb $i &
done
クライアント起動
ruby em-http-client.rb
各サーバーからのレスポンスが3, 4, 5秒後に出力されます。
非同期複数リクエストなので約5秒後にはすべてレスポンスが得られます。逐次同期的に実行していたらおよそ3 + 4 + 5 = 12秒後となっていたでしょう。
Going to sleep for 4 seconds...
Going to sleep for 3 seconds...
Going to sleep for 5 seconds...
localhost.localdomain - - [13/Dec/2014:13:58:18 JST] "GET /?duration=3 HTTP/1.1" 200 26
- -> /?duration=3
{"pid":92341,"duration":3}
localhost.localdomain - - [13/Dec/2014:13:58:18 JST] "GET /?duration=4 HTTP/1.1" 200 26
- -> /?duration=4
{"pid":92342,"duration":4}
localhost.localdomain - - [13/Dec/2014:13:58:18 JST] "GET /?duration=5 HTTP/1.1" 200 26
- -> /?duration=5
{"pid":92343,"duration":5}
その他
em-synchronyも試してみたいです。
以上。