Skip to content

Instantly share code, notes, and snippets.

@wanabe
Last active April 28, 2024 08:24
Show Gist options
  • Save wanabe/8e92cce9309dafa49733af86f87dbc3a to your computer and use it in GitHub Desktop.
Save wanabe/8e92cce9309dafa49733af86f87dbc3a to your computer and use it in GitHub Desktop.
Falcon ってどういう仕組みなのか読んでみたけれどよくわからない(未完)

免責

てきとうに読み始めててきとうに書き始めていてまだ終わっていません。 何か変なことを書いていたらすみません。

序文

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

https://github.com/socketry/falcon/blob/8ea5916671c69d11b1ff5a2c33e6f52be750668b/lib/falcon/command.rb#L14

			Top.call(*arguments)

https://github.com/socketry/falcon/blob/8ea5916671c69d11b1ff5a2c33e6f52be750668b/lib/falcon/command/top.rb#L88

					@command.call

https://github.com/socketry/falcon/blob/8ea5916671c69d11b1ff5a2c33e6f52be750668b/lib/falcon/command/top.rb#L36

				'serve' => Serve,

https://github.com/socketry/falcon/blob/8ea5916671c69d11b1ff5a2c33e6f52be750668b/lib/falcon/command/serve.rb#L122

				Async::Service::Controller.run(self.configuration, container_class: self.container_class, graceful_stop: @options[:graceful_stop])

https://github.com/socketry/falcon/blob/8ea5916671c69d11b1ff5a2c33e6f52be750668b/lib/falcon/command/serve.rb#L39

				option '--forked | --threaded | --hybrid', "Select a specific parallelism model.", key: :container, default: :forked

https://github.com/socketry/falcon/blob/8ea5916671c69d11b1ff5a2c33e6f52be750668b/lib/falcon/command/serve.rb#L87-L92

			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

https://github.com/socketry/async-container/blob/v0.18.1/lib/async/container/controller.rb#L117-L142

				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

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 で停止を抑制して
  • 先ほどの Async::HTTP::Server#accept を呼び出し
  • 実際の config.ru 内のコードを呼び出す。

Fiber

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 以外への応用、のようなことができるようになるのかもしれません。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment