てきとうに読み始めててきとうに書き始めていてまだ終わっていません。 何か変なことを書いていたらすみません。
https://github.com/socketry/falcon がどう動いているのか気になったので見てみます。
printf 'source "https://rubygems.org"\ngem "falcon"\n' > Gemfile
printf 'run { |env| [200, {"Content-Type" => "text/plain"}, ["Hello, World!\\n"]] }\n' > config.ru
bundle
bundle exec falcon serve
これだけで起動しました。
falcon
コマンドを見ていきます。
https://github.com/socketry/falcon/blob/8ea5916671c69d11b1ff5a2c33e6f52be750668b/bin/falcon#L26-L26
Falcon::Command.call
Top.call(*arguments)
@command.call
'serve' => Serve,
Async::Service::Controller.run(self.configuration, container_class: self.container_class, graceful_stop: @options[:graceful_stop])
option '--forked | --threaded | --hybrid', "Select a specific parallelism model.", key: :container, default: :forked
def container_class
case @options[:container]
...
when :forked
return Async::Container::Forked
ざっくり、Async::Service::Controller.run
に対してデフォルトで Async::Container::Forked
ストラテジを指定している、といった感じに見えます。
いったんここまで。
echo ".bundle/" > .gitignore
git init
git add Gemfile Gemfile.lock config.ru .gitignore
git commit -m init
レスポンスを返す箇所で、どのようにそこまで到達したか見てみます。
echo 'gem "debug"' >> Gemfile
sed -i.tmp -e '1irequire "debug"' -e 's/\[/debugger; [/' config.ru
bundle exec falcon serve
別のターミナルから
curl --insecure https://127.0.0.1:9292
戻って
(rdbg) bt # backtrace command
=>#0 block {|env={"protocol.http.request"=>#<Async::HTTP::...|} in <main> (2 levels) at config.ru:2
#1 Protocol::Rack::Adapter::Generic#call(request=#<Async::HTTP::Protocol::HTTP2::Request:0...) at ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/protocol-rack-0.5.1/lib/protocol/rack/adapter/generic.rb:108
#2 Protocol::HTTP::Middleware#call(request=#<Async::HTTP::Protocol::HTTP2::Request:0...) at ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/protocol-http-0.26.4/lib/protocol/http/middleware.rb:43
#3 Protocol::HTTP::ContentEncoding#call(request=#<Async::HTTP::Protocol::HTTP2::Request:0...) at ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/protocol-http-0.26.4/lib/protocol/http/content_encoding.rb:29
#4 Protocol::HTTP::Middleware#call(request=#<Async::HTTP::Protocol::HTTP2::Request:0...) at ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/protocol-http-0.26.4/lib/protocol/http/middleware.rb:43
#5 block {|request=#<Async::HTTP::Protocol::HTTP2::Request:0...|} in accept at ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/server.rb:62
#6 block in each (2 levels) at ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/protocol/http2/server.rb:57
#7 Async::Task#defer_stop at ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:269
#8 block {|task=#<Async::Task:0x0000000000000bf4 Incoming..., request=#<Async::HTTP::Protocol::HTTP2::Request:0...|} in each at ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/protocol/http2/server.rb:56
#9 block in run at ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:163
#10 block in schedule at ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:376
Async::Service::Controller.run
から始まったはずなのにそこまで辿れない。どういうことかわかりません。
もう一度 Async::Service::Controller.run
に戻ってみます。なんやかんやあって Async::Container::Controller#run
に帰結するようでした。
https://github.com/socketry/async-container/blob/v0.18.1/lib/async/container/controller.rb#L203-L208
self.start
while @container&.running?
begin
@container.wait
container = self.create_container
begin
self.setup(container)
...
end
...
container.wait_until_ready
...
# The following swap should be atomic:
old_container = @container
@container = container
https://github.com/socketry/async-container/blob/v0.18.1/lib/async/container/controller.rb#L72
@container_class.new
字面で見ていてもよくわからなくなってきたので、debugger を仕込んでみます。
[26, 35] in ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb
26|
27| def self.run(configuration, **options)
28| require "debug";debugger
29| controller = Async::Service::Controller.new(configuration.services.to_a, **options)
30|
=> 31| self.warmup
32|
33| controller.run
34| end
35|
...
[44, 53] in ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb
44| attr :services
45|
46| # Start all named services.
47| def start
48| @services.each do |service|
=> 49| service.start
50| end
51|
52| super
53| end
=>#0 block {|service=#<Falcon::Service::Server:0x00007f1916359...|} in start at ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:49
#1 [C] Array#each at ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:48
# and 25 frames (use `bt' command for all frames)
(rdbg)
[368, 377] in ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb
368| finish!
369| end
370|
371| def schedule(&block)
372| @fiber = Fiber.new(annotation: self.annotation) do
=> 373| set!
374|
375| begin
376| completed!(yield)
377| # Console.logger.debug(self) {"Task was completed with #{@children.size} children!"}
=>#0 block in schedule at ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:373
Falcon::Service::Server#start
が呼び出されたあたりで、先ほどと同じような形の backtrace に切り替わりました。
(ruby) ObjectSpace.each_object(Fiber).to_a
[#<Fiber:0x00007f54cc4ce668 (suspended)>,
#<Fiber:0x00007f54cb454080 /home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372 (resumed)>]
(ruby) ObjectSpace.each_object(Fiber).first.raise
eval error: Async::Stop
(rdbg)//home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:1:in `raise'
(rdbg)//home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:1:in `block in schedule'
nil
(rdbg) c # continue command
2m error: Falcon::Command [ec=0x7d0] [pid=711039] [2024-04-28 14:01:42 +0900]
| RuntimeError: unhandled exception
| → .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:144 in `resume'
| .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:144 in `resume'
| .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:390 in `schedule'
| .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:162 in `run'
| .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:396 in `async'
| .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:349 in `run'
| .bundle/ruby/3.2.0/gems/async-2.10.2/lib/kernel/sync.rb:26 in `Sync'
| .bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/service/server.rb:40 in `start'
| .bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:49 in `block in start'
| .bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:48 in `each'
| .bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:48 in `start'
| .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/controller.rb:203 in `run'
| .bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:33 in `run'
| .bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/command/serve.rb:122 in `call'
| .bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/command/top.rb:88 in `call'
| .bundle/ruby/3.2.0/gems/samovar-2.3.0/lib/samovar/command.rb:21 in `call'
| .bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/command.rb:14 in `call'
| .bundle/ruby/3.2.0/gems/falcon-0.47.0/bin/falcon:26 in `<top (required)>'
| .bundle/ruby/3.2.0/bin/falcon:25 in `load'
| .bundle/ruby/3.2.0/bin/falcon:25 in `<top (required)>'
| /home/wanabe/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/cli/exec.rb:58 in `load'
| /home/wanabe/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/cli/exec.rb:58 in `kernel_load'
| /home/wanabe/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/cli/exec.rb:23 in `run'
| /home/wanabe/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/cli.rb:492 in `exec'
| /home/wanabe/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/vendor/thor/lib/thor/command.rb:27 in `run'
| /home/wanabe/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/vendor/thor/lib/thor/invocation.rb:127 in `invoke_command'
| /home/wanabe/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/vendor/thor/lib/thor.rb:392 in `dispatch'
| /home/wanabe/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/cli.rb:34 in `dispatch'
| /home/wanabe/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/vendor/thor/lib/thor/base.rb:485 in `start'
| /home/wanabe/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/cli.rb:28 in `start'
| /home/wanabe/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/bundler-2.4.10/libexec/bundle:45 in `block in <top (required)>'
| /home/wanabe/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/friendly_errors.rb:117 in `with_friendly_errors'
| /home/wanabe/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/bundler-2.4.10/libexec/bundle:33 in `<top (required)>'
| /home/wanabe/.rbenv/versions/3.2.2/bin/bundle:25 in `load'
| /home/wanabe/.rbenv/versions/3.2.2/bin/bundle:25 in `<main>'
どこかで Fiber が作られていたようでした。
Fiber が出てくるとよくわからなくなるので、適当に追跡を楽にする道具を作ります。
module Fiber::Tree
attr_reader :parent
def initialize(...)
super
@parent = Fiber.current
@parent.add_chind(self)
@caller_at_init = Kernel.caller[1..-1]
end
def caller_at_init
@caller_at_init ||= []
end
def add_chind(child)
children << child
end
def children
@children ||= []
end
def ancestors
return @ancestors if @ancestors
@ancestors = []
f = self
while f
@ancestors << f
f = f.parent
end
@ancestors
end
def caller
super + Fiber.current.ancestors.map { |f| ["--- #{f} ---", *f.caller_at_init] }.flatten
end
end
Fiber.class_eval do
prepend Fiber::Tree
end
この fiber_tree を使って再度バックトレースを確認します。
$ bundle exec ruby -e 'require_relative "fiber_tree"; ARGV.replace(["serve"]); load Gem.bin_path("falcon", "falcon")'
/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/io-event-1.5.1/lib/io/event/support.rb:27: warning: IO::Buffer is experimental and both the Ruby and C interface may change in the future!
0.0s info: Falcon::Command::Serve [oid=0x758] [ec=0x76c] [pid=741259] [2024-04-28 15:12:45 +0900]
| Falcon v0.47.0 taking flight! Using Async::Container::Forked {:count=>20, :restart=>true}.
| - Binding to: #<Falcon::Endpoint https://localhost:9292/ {}>
| - To terminate: Ctrl-C or kill 741259
| - To reload configuration: kill -HUP 741259
0.03s info: Falcon::Service::Server [oid=0x7a8] [ec=0x76c] [pid=741259] [2024-04-28 15:12:45 +0900]
| Starting server on #<Falcon::Endpoint https://localhost:9292/ {}>
[1, 3] in config.ru
1| require "debug"
2| require_relative "fiber_tree"
=> 3| run { |env| debugger; [200, {"Content-Type" => "text/plain"}, ["Hello, World!\n"]] }
=>#0 block {|env={"protocol.http.request"=>#<Async::HTTP::...|} in <main> (2 levels) at config.ru:3
#1 Protocol::Rack::Adapter::Generic#call(request=#<Async::HTTP::Protocol::HTTP2::Request:0...) at ~/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/protocol-rack-0.5.1/lib/protocol/rack/adapter/generic.rb:108
# and 9 frames (use `bt' command for all frames)
(ruby) c=-1; puts Fiber.current.caller.select {|t| t !~ %r[gems/debug] }.map {|t| t =~ /\A---/ ? t : "#%-5d %s" % [c+=1, t.sub(%r[#{Dir.pwd}/], '')] }
#0 (rdbg)/config.ru:1:in `block (2 levels) in <main>'
#1 <internal:trace_point>:200:in `allow_reentry'
#2 config.ru:3:in `block (2 levels) in <main>'
#3 .bundle/ruby/3.2.0/gems/protocol-rack-0.5.1/lib/protocol/rack/adapter/generic.rb:108:in `call'
#4 .bundle/ruby/3.2.0/gems/protocol-http-0.26.4/lib/protocol/http/middleware.rb:43:in `call'
#5 .bundle/ruby/3.2.0/gems/protocol-http-0.26.4/lib/protocol/http/content_encoding.rb:29:in `call'
#6 .bundle/ruby/3.2.0/gems/protocol-http-0.26.4/lib/protocol/http/middleware.rb:43:in `call'
#7 .bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/server.rb:62:in `block in accept'
#8 .bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/protocol/http2/server.rb:57:in `block (2 levels) in each'
#9 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:269:in `defer_stop'
#10 .bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/protocol/http2/server.rb:56:in `block in each'
#11 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:163:in `block in run'
#12 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:376:in `block in schedule'
--- #<Fiber:0x00007f0d6016c550 /home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372 (resumed)> ---
#13 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `new'
#14 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `schedule'
#15 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:162:in `run'
#16 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:176:in `async'
#17 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/queue.rb:53:in `async'
#18 .bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/protocol/http2/server.rb:51:in `each'
#19 .bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/server.rb:51:in `accept'
#20 .bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/wrapper.rb:168:in `block in accept'
#21 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:163:in `block in run'
#22 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:376:in `block in schedule'
--- #<Fiber:0x00007f0d603824c0 /home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372 (suspended)> ---
#23 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `new'
#24 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `schedule'
#25 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:162:in `run'
#26 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:396:in `async'
#27 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:403:in `fiber'
#28 .bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/wrapper.rb:182:in `schedule'
#29 .bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/wrapper.rb:182:in `async'
#30 .bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/wrapper.rb:167:in `accept'
#31 .bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/generic.rb:83:in `block in accept'
#32 .bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/bound_endpoint.rb:65:in `block (2 levels) in bind'
#33 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:163:in `block in run'
#34 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:376:in `block in schedule'
--- #<Fiber:0x00007f0d60383910 /home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372 (suspended)> ---
#35 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `new'
#36 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `schedule'
#37 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:162:in `run'
#38 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:396:in `async'
#39 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:403:in `fiber'
#40 .bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/wrapper.rb:182:in `schedule'
#41 .bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/wrapper.rb:182:in `async'
#42 .bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/bound_endpoint.rb:64:in `block in bind'
#43 .bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/bound_endpoint.rb:62:in `map'
#44 .bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/bound_endpoint.rb:62:in `bind'
#45 .bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/generic.rb:82:in `accept'
#46 .bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/server.rb:69:in `run'
#47 .bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/service/server.rb:62:in `block (2 levels) in setup'
#48 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:163:in `block in run'
#49 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:376:in `block in schedule'
--- #<Fiber:0x00007f0d60487ff0 /home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372 (suspended)> ---
#50 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `new'
#51 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `schedule'
#52 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:162:in `run'
#53 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:396:in `async'
#54 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:349:in `run'
#55 .bundle/ruby/3.2.0/gems/async-2.10.2/lib/kernel/async.rb:32:in `Async'
#56 .bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/service/server.rb:59:in `block in setup'
#57 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/process.rb:74:in `block (2 levels) in fork'
#58 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/process.rb:68:in `fork'
#59 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/process.rb:68:in `block in fork'
#60 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/process.rb:105:in `initialize'
#61 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/process.rb:67:in `new'
#62 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/process.rb:67:in `fork'
#63 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/forked.rb:22:in `start'
#64 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/generic.rb:151:in `block in spawn'
--- #<Fiber:0x00007f0d6048a5e8 /home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/generic.rb:149 (suspended)> ---
#65 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/generic.rb:263:in `new'
#66 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/generic.rb:263:in `fiber'
#67 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/generic.rb:149:in `spawn'
#68 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/generic.rb:187:in `block in run'
#69 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/generic.rb:186:in `times'
#70 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/generic.rb:186:in `run'
#71 .bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/service/server.rb:56:in `setup'
#72 .bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:61:in `block in setup'
#73 .bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:60:in `each'
#74 .bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:60:in `setup'
#75 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/controller.rb:120:in `restart'
#76 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/controller.rb:96:in `start'
#77 .bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:51:in `start'
#78 .bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/controller.rb:203:in `run'
#79 .bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:32:in `run'
#80 .bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/command/serve.rb:122:in `call'
#81 .bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/command/top.rb:88:in `call'
#82 .bundle/ruby/3.2.0/gems/samovar-2.3.0/lib/samovar/command.rb:21:in `call'
#83 .bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/command.rb:14:in `call'
#84 .bundle/ruby/3.2.0/gems/falcon-0.47.0/bin/falcon:26:in `<top (required)>'
#85 -e:1:in `load'
#86 -e:1:in `<main>'
--- #<Fiber:0x00007f0d60eedc88 (suspended by resuming)> ---
nil
(rdbg)
なんだかずいぶんと Fiber が入れ子になっているようです。
server.rb と名の付くものがなんだか重要そうに見えるのでそこをピックアップしてみます。
https://github.com/socketry/falcon/blob/v0.47.0/lib/falcon/service/server.rb#L56
container.run(name: self.name, **container_options) do |instance|
https://github.com/socketry/falcon/blob/v0.47.0/lib/falcon/service/server.rb#L59
Async do |task|
https://github.com/socketry/falcon/blob/v0.47.0/lib/falcon/service/server.rb#L62
server.run
https://github.com/socketry/async-http/blob/v0.65.1/lib/async/http/server.rb#L69
@endpoint.accept(&self.method(:accept))
https://github.com/socketry/async-http/blob/v0.65.1/lib/async/http/server.rb#L51
connection.each do |request|
https://github.com/socketry/async-http/blob/v0.65.1/lib/async/http/protocol/http2/server.rb#L51
@requests&.async do |task, request|
https://github.com/socketry/async-http/blob/v0.65.1/lib/async/http/protocol/http2/server.rb#L56
task.defer_stop do
https://github.com/socketry/async-http/blob/v0.65.1/lib/async/http/protocol/http2/server.rb#L57
response = yield(request)
https://github.com/socketry/async-http/blob/v0.65.1/lib/async/http/server.rb#L62
self.call(request)
日本語でざっくり書き下すと、こんな感じかなという気がします。気がするだけです。
- サーバーのセットアップ処理で、
- Async コンテナを run し始める。
- その中で
Async do ... end
で非同期に Falcon::Server
を作成して run する。IO::Endpoint::BoundEndpoint#accept
で通信を受け付け始める。- 通信を実際に受けたときには
Async::HTTP::Server#accept
がコールバックとして呼ばれるようにセットされる。- (注:
IO::Endpoint::BoundEndpoint#accept
は「受け付け始める処理」であるのに対し、Async::HTTP::Server#accept
は「実際に受け付けた際の処理」であり、同名であっても処理のタイミングが異なる)
- (注:
Async::HTTP::Protocol::HTTP2::Server#each
で個別のリクエストを取り出し- リクエストを処理するタスクを開始したら途中で止まったりしないように
Async::Task#defer_stop
で停止を抑制して- ref: socketry/async#310
- 先ほどの
Async::HTTP::Server#accept
を呼び出し - 実際の
config.ru
内のコードを呼び出す。
Fiber が多いので、それぞれの Fiber がどこで作られたのかを見ていきます。先ほどの fiber_tree.rb にこんなメソッドを追加しました。
def <=>(fiber)
return -(fiber <=> self) unless fiber.is_a?(Fiber)
return 0 if self === fiber
return 1 if ancestors.include?(fiber)
return -1 if fiber.ancestors.include?(self)
return 0
end
これを利用して作成時のバックトレースを覗いてみます。
(ruby) Fiber.current.object_id
7020
(ruby) ObjectSpace.each_object(Fiber).sort.map {|f| [f.object_id, f.alive?, f.parent.object_id, f.caller_at_init] }.uniq{|_, *a| a}
[[1900, true, 4, []],
[6600,
true,
1900,
["/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/generic.rb:263:in `new'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/generic.rb:263:in `fiber'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/generic.rb:149:in `spawn'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/generic.rb:187:in `block in run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/generic.rb:186:in `times'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/generic.rb:186:in `run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/service/server.rb:56:in `setup'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:61:in `block in setup'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:60:in `each'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:60:in `setup'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/controller.rb:120:in `restart'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/controller.rb:96:in `start'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:51:in `start'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/controller.rb:203:in `run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:32:in `run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/command/serve.rb:122:in `call'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/command/top.rb:88:in `call'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/samovar-2.3.0/lib/samovar/command.rb:21:in `call'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/command.rb:14:in `call'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/falcon-0.47.0/bin/falcon:26:in `<top (required)>'",
"-e:1:in `load'",
"-e:1:in `<main>'"]],
[6620,
true,
6600,
["/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `new'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `schedule'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:162:in `run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:396:in `async'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:349:in `run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/kernel/async.rb:32:in `Async'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/service/server.rb:59:in `block in setup'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/process.rb:74:in `block (2 levels) in fork'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/process.rb:68:in `fork'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/process.rb:68:in `block in fork'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/process.rb:105:in `initialize'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/process.rb:67:in `new'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/process.rb:67:in `fork'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/forked.rb:22:in `start'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/generic.rb:151:in `block in spawn'"]],
[6920,
false,
1900,
["/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `new'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `schedule'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:162:in `run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:396:in `async'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:349:in `run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/kernel/sync.rb:26:in `Sync'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/service/server.rb:40:in `start'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:48:in `block in start'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:47:in `each'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:47:in `start'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-container-0.18.2/lib/async/container/controller.rb:203:in `run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-service-0.12.0/lib/async/service/controller.rb:32:in `run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/command/serve.rb:122:in `call'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/command/top.rb:88:in `call'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/samovar-2.3.0/lib/samovar/command.rb:21:in `call'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/command.rb:14:in `call'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/falcon-0.47.0/bin/falcon:26:in `<top (required)>'",
"-e:1:in `load'",
"-e:1:in `<main>'"]],
[6980,
true,
6620,
["/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `new'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `schedule'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:162:in `run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:396:in `async'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:403:in `fiber'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/wrapper.rb:182:in `schedule'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/wrapper.rb:182:in `async'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/bound_endpoint.rb:64:in `block in bind'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/bound_endpoint.rb:62:in `map'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/bound_endpoint.rb:62:in `bind'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/generic.rb:82:in `accept'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/server.rb:69:in `run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/falcon-0.47.0/lib/falcon/service/server.rb:62:in `block (2 levels) in setup'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:163:in `block in run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:376:in `block in schedule'"]],
[7000,
true,
6980,
["/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `new'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `schedule'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:162:in `run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:396:in `async'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/scheduler.rb:403:in `fiber'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/wrapper.rb:182:in `schedule'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/wrapper.rb:182:in `async'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/wrapper.rb:167:in `accept'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/generic.rb:83:in `block in accept'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/bound_endpoint.rb:65:in `block (2 levels) in bind'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:163:in `block in run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:376:in `block in schedule'"]],
[7020,
true,
7000,
["/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `new'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `schedule'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:162:in `run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:176:in `async'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/queue.rb:53:in `async'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/protocol/http2/server.rb:51:in `each'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/server.rb:51:in `accept'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/wrapper.rb:168:in `block in accept'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:163:in `block in run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:376:in `block in schedule'"]],
[7040,
true,
7000,
["/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `new'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:372:in `schedule'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:162:in `run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:176:in `async'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/protocol/http2/connection.rb:82:in `read_in_background'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/protocol/http2/connection.rb:65:in `start_connection'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/protocol/http2.rb:54:in `server'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/protocol/https.rb:42:in `server'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-http-0.65.1/lib/async/http/server.rb:47:in `accept'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/io-endpoint-0.10.2/lib/io/endpoint/wrapper.rb:168:in `block in accept'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:163:in `block in run'",
"/home/wanabe/work/prog/ruby/falcon-test/.bundle/ruby/3.2.0/gems/async-2.10.2/lib/async/task.rb:376:in `block in schedule'"]]]
親子関係を考慮すると以下のようになるように読めました。
- id: 1900
- (ルート)
- id: 6600
- (コンテナ起動)
- id: 6620
- (
Falcon::Server#run
を非同期に開始) - id: 6980
- (
IO::Endpoint::BoundEndpoint#bind
に渡されたブロックを非同期に処理) - id: 7000
- (
IO::Endpoint::Wrapper#accept
の無限ループで、コールバック処理を非同期に処理) - id: 7020
- (
Async::HTTP::Protocol::HTTP2::Server#each
で、キューにたまったリクエストを非同期に処理)
- (
- id: 7040
- (コネクションから非同期にリクエストを読み込み)
- (
- (
- (
- id: 6920
- (同期処理にするための一時的な Fiber.@bound_endpoint を取得するのに利用)
処理を細かく分けて入れ子にして、ちょっとでも時間がかかりそうなら Fiber にしてしまう、あとは Fiber Scheduler に任せる、という感じのポリシーなのかな、と読めました。
たぶん async gem や Fiber Scheduler の知識があるともうちょっとよくわかるのではないかという気がします。 コンテナとかコントローラとかの概念が全然わかってないのが致命的なのでは。 よくわかってくると、async-* gem を自作して HTTP 以外への応用、のようなことができるようになるのかもしれません。