Share
Embed
Building, Deploying, and Monitoring Ruby Web Applications with Falcon (Kaigi on Rails 2025)
Samuel Williams
October 09, 2025
Transcript
301 slides
-
Value × Scope = Impact ৼΓฦΔͱɺ͜Ε୯ͳΔࣗͷෆຬͰͳ͘ɺRubyͦͷͷ ʹؔΘΔ͜ͱͩͱؾ͖ͮ·ͨ͠ɻ Do more with
less Lot’s of Ruby users Worthwhile Effort গͳ͍ࢿݯͰଟ͘ RubyϢʔβʔଟ Ձ͋Δઓ -
Value × Scope = Impact ฒߦॲཧେ͖ͳՁΛͨΒ͠·͢ʕʕޮΛߴΊɺ৽͍͠ ΞϓϦέʔγϣϯઃܭΛՄೳʹ͠·͢ɻ Do more with
less Lot’s of Ruby users Worthwhile Effort গͳ͍ࢿݯͰଟ͘ RubyϢʔβʔଟ Ձ͋Δઓ -
Value × Scope = Impact ͦͷείʔϓڊେͰ͢ʕʕRubyੈքதͷඦສͷΞϓϦ έʔγϣϯͱ։ൃऀΛࢧ͍͑ͯ·͢ɻ Do more with
less Lot’s of Ruby users Worthwhile Effort গͳ͍ࢿݯͰଟ͘ RubyϢʔβʔଟ Ձ͋Δઓ -
Value × Scope = Impact ՁʹείʔϓΛֻ͚߹ΘͤΔͱɺΠϯύΫτ͕ੜ·Ε·͢ʕʕRubyͱͦͷ ར༻ํ๏Λมֵ͠ɺͯ͢ͷਓʹͱͬͯΑΓྑ͍ͷʹ͢ΔνϟϯεͰ͢ɻ Do more with
less Lot’s of Ruby users Worthwhile Effort গͳ͍ࢿݯͰଟ͘ RubyϢʔβʔଟ Ձ͋Δઓ -
Value × Scope = Impact େ͖ͳՁ͕͋ͬͯɺείʔϓ͕ͳ͚ΕΠϯύΫτখ͍͞ɻ ͜ͷ10ؒͰɺͦͷߟ͑ํͷॏཁੑΛ࣮ײ͠·ͨ͠ɻ Do more with
less Lot’s of Ruby users Worthwhile Effort গͳ͍ࢿݯͰଟ͘ RubyϢʔβʔଟ Ձ͋Δઓ -
In 2019, I gave a talk called “The Journey to
One Million” 2019ʹʮThe Journey to One Millionʢ100ສͷಓͷΓʣʯ ͱ͍͏ߨԋΛߦ͍·ͨ͠ɻ -
At RubyWorld Conference 2019, I talked about climate change. RubyWorld
Conference 2019Ͱɺ ؾީมಈʹ͍ͭͯߨԋ͠·ͨ͠ɻ -
Falcon is a web server that uses one fi ber
per request. FalconɺϦΫΤετ͝ͱʹ1ͭͷFiberΛ༻͢ΔΣϒαʔ όʔͰ͢ɻ -
I want you to replicate this success with con fi
dence. ͜ͷޭΛࣗ৴Λ࣋ͬͯ࠶ݱͯ͠΄͍͠ͷͰ͢ɻ -
IO::Event KQueue, EPoll, URing Fiber::Scheduler Concurrent Execution Model IO #read
#write #wait Thread #join Thread::Mutex #lock Thread::Queue #pop Addrinfo .getaddrinfo Process .wait Timeout .timeout Fiber#raise Error Handling Fiber#storage “Per-request” State Management IO::Buffer Zero-copy Memory I/O Native Coroutines (Also used for M:N threading) IO#timeout Safety Net -
Application ActiveSupport IsolatedExecutionState = : fi ber ActiveRecord #lease_connection ActionDispatch
Streaming Response ActionCable Server Adapterization Async::Cable Async::WebSocket Async::Job Async::Redis Live -
= > Booting Falcon v0.52.0 = > Rails 8.0.2 application
sta r ting in development http: / / localhost:3000 = > Run `bin/ r ails se r ve r - - help` fo r mo r e sta r tup options -
# conf i g/application. r b conf i g.active_ r
eco r d.pe r manent_connection_checkout = :disallowed conf i g.active_suppo r t.isolation_level = :f i be r # O r di r ectly if not pa r t of a Rails application: ActiveReco r d.pe r manent_connection_checkout = :disallowed ActiveSuppo r t : : IsolatedExecutionState.isolation_level = :f i be r -
# conf i g/application. r b conf i g.active_ r
eco r d.pe r manent_connection_checkout = :disallowed conf i g.active_suppo r t.isolation_level = :f i be r # O r di r ectly if not pa r t of a Rails application: ActiveReco r d.pe r manent_connection_checkout = :disallowed ActiveSuppo r t : : IsolatedExecutionState.isolation_level = :f i be r -
# conf i g/application. r b conf i g.active_ r
eco r d.pe r manent_connection_checkout = :disallowed conf i g.active_suppo r t.isolation_level = :f i be r # O r di r ectly if not pa r t of a Rails application: ActiveReco r d.pe r manent_connection_checkout = :disallowed ActiveSuppo r t : : IsolatedExecutionState.isolation_level = :f i be r -
class Pizza < ActiveReco r d : : Base validates
:name, p r esence: t r ue def cook!(du r ation = 0.001) update!(status: 'cooking') sleep(du r ation) update!(status: 'hot') end end r un do |env| r equest = Rack : : Request.new(env) pizza = Pizza.c r eate!(name: "Ma r ghe r ita", status: "cold") pizza.cook! [200, {"content - type" = > "application/json"}, [pizza.to_json]] end -
class Pizza < ActiveReco r d : : Base validates
:name, p r esence: t r ue def cook!(du r ation = 0.001) update!(status: 'cooking') sleep(du r ation) update!(status: 'hot') end end r un do |env| r equest = Rack : : Request.new(env) pizza = Pizza.c r eate!(name: "Ma r ghe r ita", status: "cold") pizza.cook! [200, {"content - type" = > "application/json"}, [pizza.to_json]] end -
class Pizza < ActiveReco r d : : Base validates
:name, p r esence: t r ue def cook!(du r ation = 0.001) update!(status: 'cooking') sleep(du r ation) update!(status: 'hot') end end r un do |env| r equest = Rack : : Request.new(env) pizza = Pizza.c r eate!(name: "Ma r ghe r ita", status: "cold") pizza.cook! [200, {"content - type" = > "application/json"}, [pizza.to_json]] end -
class Pizza < ActiveReco r d : : Base validates
:name, p r esence: t r ue def cook!(du r ation = 0.001) update!(status: 'cooking') sleep(du r ation) update!(status: 'hot') end end r un do |env| r equest = Rack : : Request.new(env) pizza = Pizza.c r eate!(name: "Ma r ghe r ita", status: "cold") pizza.cook! [200, {"content - type" = > "application/json"}, [pizza.to_json]] end -
class Pizza < ActiveReco r d : : Base validates
:name, p r esence: t r ue def cook!(du r ation = 0.001) update!(status: 'cooking') sleep(du r ation) update!(status: 'hot') end end r un do |env| r equest = Rack : : Request.new(env) pizza = Pizza.c r eate!(name: "Ma r ghe r ita", status: "cold") pizza.cook! [200, {"content - type" = > "application/json"}, [pizza.to_json]] end -
class Pizza < ActiveReco r d : : Base validates
:name, p r esence: t r ue def cook!(du r ation = 0.001) update!(status: 'cooking') sleep(du r ation) update!(status: 'hot') end end r un do |env| r equest = Rack : : Request.new(env) pizza = Pizza.c r eate!(name: "Ma r ghe r ita", status: "cold") pizza.cook! [200, {"content - type" = > "application/json"}, [pizza.to_json]] end -
4 workers, 3 threads (recommended default) Falcon vs Puma Requests/second
0 1000 2000 3000 4000 Connection Count 1 4 40 Pum a F a lcon Pum a F a lcon Pum a F a lcon 3,232 461 166 1,231 456 165 -
4 workers, 10 threads Falcon vs Puma Requests/second 0 1500
3000 4500 6000 Connection Count 40 80 160 Pum a F a lcon Pum a F a lcon Pum a F a lcon 5,341 4,779 3,232 2,214 2,241 2,223 -
We need wrap the queue with the interface expected by
ActiveJob. ActiveJob͕ظ͢ΔΠϯλʔϑΣʔεͰΩϡʔΛϥοϓ͢Δඞ ཁ͕͋Γ·͢ɻ -
Async::Job::Queue Job Data Job Data Enqueue Dequeue ActiveJob Seri a
lize ActiveJob Deseri a lize Perform Now Perform L a ter -
It’s a nice design because we can directly execute the
jobs. δϣϒΛ࣮ߦͰ͖ΔͷͰɺ༏Εͨઃܭʹͳ͍ͬͯ·͢ɻ -
module ActiveJob module QueueAdapte r s # = Sidekiq adapte
r fo r Active Job class SidekiqAdapte r < Abst r actAdapte r def enqueue(job) # :nodoc: job.p r ovide r _job_id = JobW r appe r .set( w r apped: job.class, queue: job.queue_name ).pe r fo r m_async(job.se r ialize) end class JobW r appe r # :nodoc: include Sidekiq : : Wo r ke r def pe r fo r m(job_data) Base.execute job_data.me r ge("p r ovide r _job_id" = > jid) end end end end -
module ActiveJob module QueueAdapte r s # = Sidekiq adapte
r fo r Active Job class SidekiqAdapte r < Abst r actAdapte r def enqueue(job) # :nodoc: job.p r ovide r _job_id = JobW r appe r .set( w r apped: job.class, queue: job.queue_name ).pe r fo r m_async(job.se r ialize) end class JobW r appe r # :nodoc: include Sidekiq : : Wo r ke r def pe r fo r m(job_data) Base.execute job_data.me r ge("p r ovide r _job_id" = > jid) end end end end -
module ActiveJob module QueueAdapte r s # = Sidekiq adapte
r fo r Active Job class SidekiqAdapte r < Abst r actAdapte r def enqueue(job) # :nodoc: job.p r ovide r _job_id = JobW r appe r .set( w r apped: job.class, queue: job.queue_name ).pe r fo r m_async(job.se r ialize) end class JobW r appe r # :nodoc: include Sidekiq : : Wo r ke r def pe r fo r m(job_data) Base.execute job_data.me r ge("p r ovide r _job_id" = > jid) end end end end -
module Async module Job module Adapte r module ActiveJob #
An executo r fo r p r ocessing jobs using `ActiveJob`. class Executo r # Initialize the executo r with an optional delegate. def initialize(delegate = nil) @delegate = delegate end # Execute a job with the given data. # @pa r amete r job_data [Hash] Se r ialized job data f r om ActiveJob. def execute(job_data) : : ActiveJob : : Callbacks. r un_callbacks(:execute) do job = : : ActiveJob : : Base.dese r ialize(job_data) begin job.pe r fo r m_now r escue = > e r r o r r r r r r -
# Initialize the executo r with an optional delegate. def
initialize(delegate = nil) @delegate = delegate end # Execute a job with the given data. # @pa r amete r job_data [Hash] Se r ialized job data f r om ActiveJob. def execute(job_data) : : ActiveJob : : Callbacks. r un_callbacks(:execute) do job = : : ActiveJob : : Base.dese r ialize(job_data) begin job.pe r fo r m_now r escue = > e r r o r # Igno r e, as ActiveJob has al r eady logged the e r r o r . end end end -
# Initialize the executo r with an optional delegate. def
initialize(delegate = nil) @delegate = delegate end # Execute a job with the given data. # @pa r amete r job_data [Hash] Se r ialized job data f r om ActiveJob. def execute(job_data) : : ActiveJob : : Callbacks. r un_callbacks(:execute) do job = : : ActiveJob : : Base.dese r ialize(job_data) begin job.pe r fo r m_now r escue = > e r r o r # Igno r e, as ActiveJob has al r eady logged the e r r o r . end end end -
# conf i g/initialize r s/async_job. r b Rails.application.conf i
gu r e do conf i g.async_job.def i ne_queue "default" do enqueue Async : : Job : : P r ocesso r : : Agg r egate dequeue Async : : Job : : P r ocesso r : : Redis end conf i g.async_job.def i ne_queue "local" do dequeue Async : : Job : : P r ocesso r : : Inline end end -
# conf i g/initialize r s/async_job. r b Rails.application.conf i
gu r e do conf i g.async_job.def i ne_queue "default" do enqueue Async : : Job : : P r ocesso r : : Agg r egate dequeue Async : : Job : : P r ocesso r : : Redis end conf i g.async_job.def i ne_queue "local" do dequeue Async : : Job : : P r ocesso r : : Inline end end -
# conf i g/initialize r s/async_job. r b Rails.application.conf i
gu r e do conf i g.async_job.def i ne_queue "default" do enqueue Async : : Job : : P r ocesso r : : Agg r egate dequeue Async : : Job : : P r ocesso r : : Redis end conf i g.async_job.def i ne_queue "local" do dequeue Async : : Job : : P r ocesso r : : Inline end end -
class AsyncJobBenchma r kJob < ActiveJob : : Base self.queue_adapte
r = :async_job queue_as :default def pe r fo r m sleep(0.001) end end -
class AsyncJobBenchma r kJob < ActiveJob : : Base self.queue_adapte
r = :async_job queue_as :default def pe r fo r m sleep(0.001) end end -
class AsyncJobBenchma r kJob < ActiveJob : : Base self.queue_adapte
r = :async_job queue_as :default def pe r fo r m sleep(0.001) end end -
1 client, 1 worker, 1ms sleep per job. Sidekick vs
Async::Job Jobs/second 0 7500 15000 22500 30000 Enqueue Dequeue Sidekiq Async::Job Sidekiq Async::Job 6,000 28,000 4,100 22,000 -
(User reported comparison) SolidQueue vs Async::Job URLs cr a wled/second
0 6.5 13 19.5 26 SolidQueue Async::Job 25 8.3 -
class JobExecution < ApplicationReco r d afte r _c r
eate_commit - > { b r oadcast_append_to "job_executions" } end -
class MyJob < ApplicationJob queue_as "default" def pe r fo
r m(*a r guments) JobExecution.c r eate!(name: self.class.name, data: { a r guments: a r guments, }) end end -
class HomeCont r olle r < ApplicationCont r olle r
def index @job_executions = JobExecution.all end def execute job = MyJob if queue = pa r ams[:queue] job = job.set(queue: queue) end job.pe r fo r m_late r (queued_to: queue) end end -
<h1>Async Job < / h1> <p>This is a simple example
of how to use the async job gem. You can use the fo r m below to submit a job to the queue. The job will be executed in the backg r ound and the r esults will be displayed in the table below. < / p> <fo r m action="/execute" method="post"> <select name="queue"> <% Rails.application.conf i g.async_job.def i nitions.each do |name, _| %> <option value="<%= name %>"><%= name %> < / option> <% end %> < / select> <input type="submit" value="Submit" / > < / fo r m> <h2>Job Executions < / h2> <%= tu r bo_st r eam_f r om "job_executions" %> <table> <thead> r -
<h1>Async Job < / h1> <p>This is a simple example
of how to use the async job gem. You can use the fo r m below to submit a job to the queue. The job will be executed in the backg r ound and the r esults will be displayed in the table below. < / p> <fo r m action="/execute" method="post"> <select name="queue"> <% Rails.application.conf i g.async_job.def i nitions.each do |name, _| %> <option value="<%= name %>"><%= name %> < / option> <% end %> < / select> <input type="submit" value="Submit" / > < / fo r m> <h2>Job Executions < / h2> <%= tu r bo_st r eam_f r om "job_executions" %> <table> <thead> r -
<% end %> < / select> <input type="submit" value="Submit" /
> < / fo r m> <h2>Job Executions < / h2> <%= tu r bo_st r eam_f r om "job_executions" %> <table> <thead> <t r > <th>ID < / th> <th>Name < / th> <th>Data < / th> < / t r > < / thead> <tbody id="job_executions"> <%= r ende r @job_executions %> < / tbody> < / table> -
Successfully upg r aded to WebSocket (REQUEST_METHOD : GET, HTTP_CONNECTION
: Upg r ade, HTTP_UPGRADE : websocket) Tu r bo : : St r eamsChannel is t r ansmitting the subsc r iption conf i r mation Tu r bo : : St r eamsChannel is st r eaming f r om job_executions -
Successfully upg r aded to WebSocket (REQUEST_METHOD : GET, HTTP_CONNECTION
: Upg r ade, HTTP_UPGRADE : websocket) Tu r bo : : St r eamsChannel is t r ansmitting the subsc r iption conf i r mation Tu r bo : : St r eamsChannel is st r eaming f r om job_executions Sta r ted POST "/execute" fo r : : 1 at 2025-08-02 16 : 50 : 56 +1200 P r ocessing by HomeCont r olle r #execute as TURBO_STREAM Pa r amete r s: {"queue" = > "default"} [ActiveJob] Enqueued MyJob (Job ID : 069bf564-c358-4da8-b255-13be3051a112) to AsyncJob(default) with a r guments: {queued_to: "default"} [ActiveJob] ↳ app/cont r olle r s/home_cont r olle r . r b:13:in 'HomeCont r olle r #execute' No template found fo r HomeCont r olle r #execute, r ende r ing head :no_content Completed 204 No Content in 15ms (ActiveReco r d: 0.0ms (0 que r ies, 0 cached) | GC : 0.2ms) Tu r bo : : St r eamsChannel t r ansmitting "<tu r bo - st r eam action=\"append\" ta r get=\"job_executions\"><template><t r id=\"job_execution_1\">\n\t<td>1 < / td>\n\t<td>MyJob < / td>\n\t<td>{"a r guments" => [{"queued_to" => "default"}]} < / td>\n < / t r > < / template> < / tu r bo - st r eam>" (via st r eamed f r om job_executions) -
Successfully upg r aded to WebSocket (REQUEST_METHOD : GET, HTTP_CONNECTION
: Upg r ade, HTTP_UPGRADE : websocket) Tu r bo : : St r eamsChannel is t r ansmitting the subsc r iption conf i r mation Tu r bo : : St r eamsChannel is st r eaming f r om job_executions Sta r ted POST "/execute" fo r : : 1 at 2025-08-02 16 : 50 : 56 +1200 P r ocessing by HomeCont r olle r #execute as TURBO_STREAM Pa r amete r s: {"queue" = > "default"} [ActiveJob] Enqueued MyJob (Job ID : 069bf564-c358-4da8-b255-13be3051a112) to AsyncJob(default) with a r guments: {queued_to: "default"} [ActiveJob] ↳ app/cont r olle r s/home_cont r olle r . r b:13:in 'HomeCont r olle r #execute' No template found fo r HomeCont r olle r #execute, r ende r ing head :no_content Completed 204 No Content in 15ms (ActiveReco r d: 0.0ms (0 que r ies, 0 cached) | GC : 0.2ms) Tu r bo : : St r eamsChannel t r ansmitting "<tu r bo - st r eam action=\"append\" ta r get=\"job_executions\"><template><t r id=\"job_execution_1\">\n\t<td>1 < / td>\n\t<td>MyJob < / td>\n\t<td>{"a r guments" => [{"queued_to" => "default"}]} < / td>\n < / t r > < / template> < / tu r bo - st r eam>" (via st r eamed f r om job_executions) -
Successfully upg r aded to WebSocket (REQUEST_METHOD : GET, HTTP_CONNECTION
: Upg r ade, HTTP_UPGRADE : websocket) Tu r bo : : St r eamsChannel is t r ansmitting the subsc r iption conf i r mation Tu r bo : : St r eamsChannel is st r eaming f r om job_executions Sta r ted POST "/execute" fo r : : 1 at 2025-08-02 16 : 50 : 56 +1200 P r ocessing by HomeCont r olle r #execute as TURBO_STREAM Pa r amete r s: {"queue" = > "default"} [ActiveJob] Enqueued MyJob (Job ID : 069bf564-c358-4da8-b255-13be3051a112) to AsyncJob(default) with a r guments: {queued_to: "default"} [ActiveJob] ↳ app/cont r olle r s/home_cont r olle r . r b:13:in 'HomeCont r olle r #execute' No template found fo r HomeCont r olle r #execute, r ende r ing head :no_content Completed 204 No Content in 15ms (ActiveReco r d: 0.0ms (0 que r ies, 0 cached) | GC : 0.2ms) Tu r bo : : St r eamsChannel t r ansmitting "<tu r bo - st r eam action=\"append\" ta r get=\"job_executions\"><template><t r id=\"job_execution_1\">\n\t<td>1 < / td>\n\t<td>MyJob < / td>\n\t<td>{"a r guments" => [{"queued_to" => "default"}]} < / td>\n < / t r > < / template> < / tu r bo - st r eam>" (via st r eamed f r om job_executions) -
1 process, 1000 clients, 20 broadcasts. ActionCable vs Async::Cable Mess
a ges/second 0 20000 40000 60000 80000 Mess a ge ActionC a ble Async::C a ble 80,000 32,000 -
class St r eamingCont r olle r < ApplicationCont r
olle r def st r eam body = p r oc do |st r eam| 10.downto(1) do |i| st r eam.w r ite " # { i} bottles of bee r on the wall\n" sleep 1 st r eam.w r ite " # { i} bottles of bee r \n" sleep 1 st r eam.w r ite "Take one down, pass it a r ound\n" sleep 1 st r eam.w r ite " # { i - 1} bottles of bee r on the wall\n" sleep 1 end end self. r esponse = Rack : : Response[200, {"content - type" = > "text/plain"}, body] end end -
class St r eamingCont r olle r < ApplicationCont r
olle r def st r eam body = p r oc do |st r eam| 10.downto(1) do |i| st r eam.w r ite " # { i} bottles of bee r on the wall\n" sleep 1 st r eam.w r ite " # { i} bottles of bee r \n" sleep 1 st r eam.w r ite "Take one down, pass it a r ound\n" sleep 1 st r eam.w r ite " # { i - 1} bottles of bee r on the wall\n" sleep 1 end end self. r esponse = Rack : : Response[200, {"content - type" = > "text/plain"}, body] end end -
class St r eamingCont r olle r < ApplicationCont r
olle r def st r eam body = p r oc do |st r eam| 10.downto(1) do |i| st r eam.w r ite " # { i} bottles of bee r on the wall\n" sleep 1 st r eam.w r ite " # { i} bottles of bee r \n" sleep 1 st r eam.w r ite "Take one down, pass it a r ound\n" sleep 1 st r eam.w r ite " # { i - 1} bottles of bee r on the wall\n" sleep 1 end end self. r esponse = Rack : : Response[200, {"content - type" = > "text/plain"}, body] end end -
10 bottles of bee r on the wall 10 bottles
of bee r Take one down, pass it a r ound 9 bottles of bee r on the wall 9 bottles of bee r on the wall 9 bottles of bee r Take one down, pass it a r ound 8 bottles of bee r on the wall 8 bottles of bee r on the wall 8 bottles of bee r Take one down, pass it a r ound 7 bottles of bee r on the wall 7 bottles of bee r on the wall 7 bottles of bee r Take one down, pass it a r ound 6 bottles of bee r on the wall 6 bottles of bee r on the wall 6 bottles of bee r Take one down, pass it a r ound -
Summary Building with Falcon ✅ HTTP/2 + TLS with loc
a lhost development certi f ic a tes. -
Summary Building with Falcon ✅ HTTP/2 + TLS with loc
a lhost development certi f ic a tes. ✅ ActiveRecord fully supported (in f iber mode). -
Summary Building with Falcon ✅ HTTP/2 + TLS with loc
a lhost development certi f ic a tes. ✅ ActiveRecord fully supported (in f iber mode). ✅ ActiveJob with Async support using Async::Job::Ad a pter::ActiveJob. -
Summary Building with Falcon ✅ HTTP/2 + TLS with loc
a lhost development certi f ic a tes. ✅ ActiveRecord fully supported (in f iber mode). ✅ ActiveJob with Async support using Async::Job::Ad a pter::ActiveJob. ✅ ActionC a ble repl a ced by Async::C a ble for improved perform a nce a nd HTTP/2 WebSockets. -
Summary Building with Falcon ✅ HTTP/2 + TLS with loc
a lhost development certi f ic a tes. ✅ ActiveRecord fully supported (in f iber mode). ✅ ActiveJob with Async support using Async::Job::Ad a pter::ActiveJob. ✅ ActionC a ble repl a ced by Async::C a ble for improved perform a nce a nd HTTP/2 WebSockets. ✅ Re a l-time Stre a ming a nd Inter a ctively using R a ck 3. -
# ! /us r /bin/env falcon - host # f
r ozen_st r ing_lite r al: t r ue r equi r e "falcon/envi r onment/ r ack" r equi r e "falcon/envi r onment/lets_enc r ypt_tls" r equi r e "falcon/envi r onment/supe r viso r " se r vice " w w w .example.com" do include Falcon : : Envi r onment : : Rack include Falcon : : Envi r onment : : LetsEnc r yptTLS end -
# ! /us r /bin/env falcon - host # f
r ozen_st r ing_lite r al: t r ue r equi r e "falcon/envi r onment/ r ack" r equi r e "falcon/envi r onment/lets_enc r ypt_tls" r equi r e "falcon/envi r onment/supe r viso r " se r vice " w w w .example.com" do include Falcon : : Envi r onment : : Rack include Falcon : : Envi r onment : : LetsEnc r yptTLS end -
# ! /us r /bin/env falcon - host # f
r ozen_st r ing_lite r al: t r ue r equi r e "falcon/envi r onment/ r ack" r equi r e "falcon/envi r onment/lets_enc r ypt_tls" r equi r e "falcon/envi r onment/supe r viso r " se r vice " w w w .example.com" do include Falcon : : Envi r onment : : Rack include Falcon : : Envi r onment : : LetsEnc r yptTLS end -
# ! /us r /bin/env falcon - host # f
r ozen_st r ing_lite r al: t r ue r equi r e "falcon/envi r onment/ r ack" r equi r e "falcon/envi r onment/lets_enc r ypt_tls" r equi r e "falcon/envi r onment/supe r viso r " se r vice " w w w .example.com" do include Falcon : : Envi r onment : : Rack include Falcon : : Envi r onment : : LetsEnc r yptTLS end -
> bundle exec ./falcon. r b 0.0s info: Falcon :
: Command : : Host | Falcon Host v0.52.0 taking flight! | - Conf i gu r ation: ./falcon. r b | - To te r minate: Ct r l-C o r kill 87272 | - To r eload: kill -HUP 87272 0.07s info: Async : : Containe r : : Notify : : Console | {status: "Initializing cont r olle r . . . "} 0.07s info: Falcon : : Se r vice : : Se r ve r | Sta r ting w w w .example.com on #<Falcon : : P r oxyEndpoint p r otocol=Async : : HTTP : : P r otocol : : HTTP2 endpoint=unix:/Use r s/samuel/Develope r / socket r y/ w w w .example.com/application.ipc> 0.07s info: Async : : Se r vice : : Cont r olle r | Cont r olle r sta r ting . . . 0.58s info: Async : : Containe r : : Notify : : Console | { r eady: t r ue, size: 11} 0.59s info: Async : : Se r vice : : Cont r olle r | Cont r olle r sta r ted . . . -
> bundle exec ./falcon. r b 0.0s info: Falcon :
: Command : : Host | Falcon Host v0.52.0 taking flight! | - Conf i gu r ation: ./falcon. r b | - To te r minate: Ct r l-C o r kill 87272 | - To r eload: kill -HUP 87272 0.07s info: Async : : Containe r : : Notify : : Console | {status: "Initializing cont r olle r . . . "} 0.07s info: Falcon : : Se r vice : : Se r ve r | Sta r ting w w w .example.com on #<Falcon : : P r oxyEndpoint p r otocol=Async : : HTTP : : P r otocol : : HTTP2 endpoint=unix:/Use r s/samuel/Develope r / socket r y/ w w w .example.com/application.ipc> 0.07s info: Async : : Se r vice : : Cont r olle r | Cont r olle r sta r ting . . . 0.58s info: Async : : Containe r : : Notify : : Console | { r eady: t r ue, size: 11} 0.59s info: Async : : Se r vice : : Cont r olle r | Cont r olle r sta r ted . . . -
# ! /us r /bin/env falcon - host # f
r ozen_st r ing_lite r al: t r ue r equi r e "falcon/envi r onment/ r ack" r equi r e "falcon/envi r onment/lets_enc r ypt_tls" r equi r e "falcon/envi r onment/supe r viso r " se r vice " w w w .example.com" do include Falcon : : Envi r onment : : Rack po r t {ENV.fetch("PORT", 3000).to_i} endpoint {Async : : HTTP : : Endpoint.pa r se("http: / / localhost", po r t: po r t)} end -
# ! /us r /bin/env falcon - host # f
r ozen_st r ing_lite r al: t r ue r equi r e "falcon/envi r onment/ r ack" r equi r e "falcon/envi r onment/lets_enc r ypt_tls" r equi r e "falcon/envi r onment/supe r viso r " se r vice " w w w .example.com" do include Falcon : : Envi r onment : : Rack po r t {ENV.fetch("PORT", 3000).to_i} endpoint {Async : : HTTP : : Endpoint.pa r se("http: / / localhost", po r t: po r t)} end -
> bundle exec ./falcon. r b 0.0s info: Falcon :
: Command : : Host | Falcon Host v0.52.0 taking flight! | - Conf i gu r ation: ./falcon. r b | - To te r minate: Ct r l-C o r kill 87577 | - To r eload: kill -HUP 87577 0.07s info: Async : : Containe r : : Notify : : Console | {status: "Initializing cont r olle r . . . "} 0.07s info: Falcon : : Se r vice : : Se r ve r | Sta r ting w w w .example.com on #<Async : : HTTP : : Endpoint http: / / localhost:3000/ {po r t: 3000}> 0.07s info: Async : : Se r vice : : Cont r olle r | Cont r olle r sta r ting . . . 0.6s info: Async : : Containe r : : Notify : : Console | { r eady: t r ue, size: 11} 0.6s info: Async : : Se r vice : : Cont r olle r | Cont r olle r sta r ted . . . -
> bundle exec ./falcon. r b 0.0s info: Falcon :
: Command : : Host | Falcon Host v0.52.0 taking flight! | - Conf i gu r ation: ./falcon. r b | - To te r minate: Ct r l-C o r kill 87577 | - To r eload: kill -HUP 87577 0.07s info: Async : : Containe r : : Notify : : Console | {status: "Initializing cont r olle r . . . "} 0.07s info: Falcon : : Se r vice : : Se r ve r | Sta r ting w w w .example.com on #<Async : : HTTP : : Endpoint http: / / localhost:3000/ {po r t: 3000}> 0.07s info: Async : : Se r vice : : Cont r olle r | Cont r olle r sta r ting . . . 0.6s info: Async : : Containe r : : Notify : : Console | { r eady: t r ue, size: 11} 0.6s info: Async : : Se r vice : : Cont r olle r | Cont r olle r sta r ted . . . -
# ! /us r /bin/env falcon - host # f
r ozen_st r ing_lite r al: t r ue r equi r e "falcon/envi r onment/ r ack" r equi r e "falcon/envi r onment/lets_enc r ypt_tls" r equi r e "falcon/envi r onment/supe r viso r " se r vice " w w w .example.com" do include Falcon : : Envi r onment : : Rack include Falcon : : Envi r onment : : LetsEnc r yptTLS po r t {ENV.fetch("PORT", 3000).to_i} endpoint {Async : : HTTP : : Endpoint.pa r se("http: / / localhost", po r t: po r t)} end se r vice "backg r ound - jobs" do include Async : : Job : : Adapte r : : ActiveJob : : Envi r onment end -
# ! /us r /bin/env falcon - host # f
r ozen_st r ing_lite r al: t r ue r equi r e "falcon/envi r onment/ r ack" r equi r e "falcon/envi r onment/lets_enc r ypt_tls" r equi r e "falcon/envi r onment/supe r viso r " se r vice " w w w .example.com" do include Falcon : : Envi r onment : : Rack include Falcon : : Envi r onment : : LetsEnc r yptTLS po r t {ENV.fetch("PORT", 3000).to_i} endpoint {Async : : HTTP : : Endpoint.pa r se("http: / / localhost", po r t: po r t)} end se r vice "backg r ound - jobs" do include Async : : Job : : Adapte r : : ActiveJob : : Envi r onment end -
> pst r ee 88602 -+= 88602 samuel r uby
/Use r s/samuel/.gem/ r uby/3.4.5/bin/falcon - host ./falcon. r b | - - - 88603 samuel w w w .example.com (C=0/0 R=0/0 L=0.0) | - - - 88604 samuel w w w .example.com (C=0/0 R=0/0 L=0.0) | - - - 88605 samuel w w w .example.com (C=0/0 R=0/0 L=0.0) | - - - 88606 samuel w w w .example.com (C=0/0 R=0/0 L=0.0) | - - - 88607 samuel backg r ound - jobs (default R=0 D=0 P=0/0, local) | - - - 88608 samuel backg r ound - jobs (default R=0 D=0 P=0/0, local) | - - - 88609 samuel backg r ound - jobs (default R=0 D=0 P=0/0, local) \ - - - 88610 samuel backg r ound - jobs (default R=0 D=0 P=0/0, local) -
> pst r ee 88602 -+= 88602 samuel r uby
/Use r s/samuel/.gem/ r uby/3.4.5/bin/falcon - host ./falcon. r b | - - - 88603 samuel w w w .example.com (C=0/0 R=0/0 L=0.0) | - - - 88604 samuel w w w .example.com (C=0/0 R=0/0 L=0.0) | - - - 88605 samuel w w w .example.com (C=0/0 R=0/0 L=0.0) | - - - 88606 samuel w w w .example.com (C=0/0 R=0/0 L=0.0) | - - - 88607 samuel backg r ound - jobs (default R=0 D=0 P=0/0, local) | - - - 88608 samuel backg r ound - jobs (default R=0 D=0 P=0/0, local) | - - - 88609 samuel backg r ound - jobs (default R=0 D=0 P=0/0, local) \ - - - 88610 samuel backg r ound - jobs (default R=0 D=0 P=0/0, local) -
> pst r ee 88602 -+= 88602 samuel r uby
/Use r s/samuel/.gem/ r uby/3.4.5/bin/falcon - host ./falcon. r b | - - - 88603 samuel w w w .example.com (C=0/0 R=0/0 L=0.0) | - - - 88604 samuel w w w .example.com (C=0/0 R=0/0 L=0.0) | - - - 88605 samuel w w w .example.com (C=0/0 R=0/0 L=0.0) | - - - 88606 samuel w w w .example.com (C=0/0 R=0/0 L=0.0) | - - - 88607 samuel backg r ound - jobs (default R=0 D=0 P=0/0, local) | - - - 88608 samuel backg r ound - jobs (default R=0 D=0 P=0/0, local) | - - - 88609 samuel backg r ound - jobs (default R=0 D=0 P=0/0, local) \ - - - 88610 samuel backg r ound - jobs (default R=0 D=0 P=0/0, local) -
> falcon vi r tual /s r v/http/*/falcon. r b
0.0s info: Falcon : : Command : : Vi r tual | Falcon Vi r tual v0.52.0 taking flight! | - Running on r uby 3.4.5 (2025-07-16 r evision 20cda200d3) +PRISM | - To te r minate: Ct r l-C o r kill 92831 | - To r eload all sites: kill -HUP 92831 . . . -
# /etc/systemd/system/falcon.se r vice [Unit] Desc r iption=Falcon Vi r
tual Web Se r ve r Afte r =netwo r k.ta r get [Se r vice] Type=notify Envi r onment=VARIANT=p r oduction # Envi r onment=CONSOLE_LEVEL=debug ExecSta r t=/us r /bin/falcon vi r tual "/s r v/http/*/falcon. r b" [Install] WantedBy=multi - use r .ta r get -
# /etc/systemd/system/falcon.se r vice [Unit] Desc r iption=Falcon Vi r
tual Web Se r ve r Afte r =netwo r k.ta r get [Se r vice] Type=notify Envi r onment=VARIANT=p r oduction # Envi r onment=CONSOLE_LEVEL=debug ExecSta r t=/us r /bin/falcon vi r tual "/s r v/http/*/falcon. r b" [Install] WantedBy=multi - use r .ta r get -
# /etc/systemd/system/falcon.se r vice [Unit] Desc r iption=Falcon Vi r
tual Web Se r ve r Afte r =netwo r k.ta r get [Se r vice] Type=notify Envi r onment=VARIANT=p r oduction # Envi r onment=CONSOLE_LEVEL=debug ExecSta r t=/us r /bin/falcon vi r tual "/s r v/http/*/falcon. r b" [Install] WantedBy=multi - use r .ta r get -
containe r s: - name: my - app image: my
- app - image:latest env: - name: NOTIFY_LOG value: "/tmp/notify.log" po r ts: - containe r Po r t: 9292 r eadinessP r obe: exec: command: ["bundle", "exec", "bake", "async:containe r :notify:log: r eady?"] initialDelaySeconds: 5 pe r iodSeconds: 5 failu r eTh r eshold: 12 -
containe r s: - name: my - app image: my
- app - image:latest env: - name: NOTIFY_LOG value: "/tmp/notify.log" po r ts: - containe r Po r t: 9292 r eadinessP r obe: exec: command: ["bundle", "exec", "bake", "async:containe r :notify:log: r eady?"] initialDelaySeconds: 5 pe r iodSeconds: 5 failu r eTh r eshold: 12 -
containe r s: - name: my - app image: my
- app - image:latest env: - name: NOTIFY_LOG value: "/tmp/notify.log" po r ts: - containe r Po r t: 9292 r eadinessP r obe: exec: command: ["bundle", "exec", "bake", "async:containe r :notify:log: r eady?"] initialDelaySeconds: 5 pe r iodSeconds: 5 failu r eTh r eshold: 12 -
For liveness probe, application speci fi c is better. Liveness
ProbeʹɺΞϓϦέʔγϣϯݻ༗ͷͷΛ͏ํ͕ ·͍͠Ͱ͢ɻ -
> cu r l https: / / localhost:3000/up <!DOCTYPE html><html><body
style="backg r ound - colo r : g r een"> < / body> < / html> -
livenessP r obe: httpGet: path: /up po r t: 3000
initialDelaySeconds: 10 pe r iodSeconds: 10 failu r eTh r eshold: 3 -
Summary Deploying with Falcon ✅ B a sic hosting using
falcon. r b service f iles. -
Summary Deploying with Falcon ✅ B a sic hosting using
falcon. r b service f iles. ✅ C a n support multiple services for simpli f ied deployment. -
Summary Deploying with Falcon ✅ B a sic hosting using
falcon. r b service f iles. ✅ C a n support multiple services for simpli f ied deployment. ✅ Virtu a l hosting using multiple falcon. r b service f iles. -
Summary Deploying with Falcon ✅ B a sic hosting using
falcon. r b service f iles. ✅ C a n support multiple services for simpli f ied deployment. ✅ Virtu a l hosting using multiple falcon. r b service f iles. ✅ Direct support for systemd + NOTIFY_SOCKET. -
Summary Deploying with Falcon ✅ B a sic hosting using
falcon. r b service f iles. ✅ C a n support multiple services for simpli f ied deployment. ✅ Virtu a l hosting using multiple falcon. r b service f iles. ✅ Direct support for systemd + NOTIFY_SOCKET. ✅ Decent support for Kubernetes using re a diness probe + NOTIFY_LOG. -
2.01s wa r n: Async : : Containe r :
: Fo r ked | Child failed health check! | { | "child": { | "name": "SleepSe r vice", | "pid": 70187, | “status": null | }, | "age": 2.0107369998004287, | "health_check_timeout": 2 | } 2.02s e r r o r : Async : : Containe r : : Fo r ked | { | "status": "pid 70187 SIGKILL (signal 9)" | } -
se r vice “ w w w .example.com” do #
. . . othe r conf i gu r ation . . . include Async : : Containe r : : Supe r viso r : : Supe r vised end se r vice "supe r viso r " do include Async : : Containe r : : Supe r viso r : : Envi r onment monito r s do [Async : : Containe r : : Supe r viso r : : Memo r yMonito r .new( # The inte r val at which to check fo r memo r y leaks. inte r val: 1, # The total size limit of all p r ocesses: maximum_size_limit: 1024 * 1024 * 400, # 400 MB )] end end -
se r vice “ w w w .example.com” do #
. . . othe r conf i gu r ation . . . include Async : : Containe r : : Supe r viso r : : Supe r vised end se r vice "supe r viso r " do include Async : : Containe r : : Supe r viso r : : Envi r onment monito r s do [Async : : Containe r : : Supe r viso r : : Memo r yMonito r .new( # The inte r val at which to check fo r memo r y leaks. inte r val: 1, # The total size limit of all p r ocesses: maximum_size_limit: 1024 * 1024 * 400, # 400 MB )] end end -
se r vice “ w w w .example.com” do #
. . . othe r conf i gu r ation . . . include Async : : Containe r : : Supe r viso r : : Supe r vised end se r vice "supe r viso r " do include Async : : Containe r : : Supe r viso r : : Envi r onment monito r s do [Async : : Containe r : : Supe r viso r : : Memo r yMonito r .new( # The inte r val at which to check fo r memo r y leaks. inte r val: 1, # The total size limit of all p r ocesses: maximum_size_limit: 1024 * 1024 * 400, # 400 MB )] end end -
se r vice “ w w w .example.com” do #
. . . othe r conf i gu r ation . . . include Async : : Containe r : : Supe r viso r : : Supe r vised end se r vice "supe r viso r " do include Async : : Containe r : : Supe r viso r : : Envi r onment monito r s do [Async : : Containe r : : Supe r viso r : : Memo r yMonito r .new( # The inte r val at which to check fo r memo r y leaks. inte r val: 1, # The total size limit of all p r ocesses: maximum_size_limit: 1024 * 1024 * 400, # 400 MB )] end end -
4.07s e r r o r : Async : :
Containe r : : Supe r viso r : : Memo r yMonito r | Memo r y leak detected in p r ocess: | { | "p r ocess_id": 68020, | "monito r ": { | "p r ocess_id": 68020, | "cu r r ent_size": 453509120, | "maximum_size": null, | "maximum_size_limit": 419430400, | "th r eshold_size": 10485760, | "inc r ease_count": 0, | "inc r ease_limit": 20 | } | } -
r equi r e 't r aces' class MyClass def
my_method puts "Hello Wo r ld" end end # If t r acing is disabled, this is a no - op. T r aces : : P r ovide r (MyClass) do def my_method att r ibutes = { 'foo' = > 'ba r ' } T r aces.t r ace('my_method', att r ibutes: att r ibutes) do supe r end end end MyClass.new.my_method -
r equi r e 't r aces' class MyClass def
my_method puts "Hello Wo r ld" end end # If t r acing is disabled, this is a no - op. T r aces : : P r ovide r (MyClass) do def my_method att r ibutes = { 'foo' = > 'ba r ' } T r aces.t r ace('my_method', att r ibutes: att r ibutes) do supe r end end end MyClass.new.my_method -
r equi r e 't r aces' class MyClass def
my_method puts "Hello Wo r ld" end end # If t r acing is disabled, this is a no - op. T r aces : : P r ovide r (MyClass) do def my_method att r ibutes = { 'foo' = > 'ba r ' } T r aces.t r ace('my_method', att r ibutes: att r ibutes) do supe r end end end MyClass.new.my_method -
r equi r e 't r aces' class MyClass def
my_method puts "Hello Wo r ld" end end # If t r acing is disabled, this is a no - op. T r aces : : P r ovide r (MyClass) do def my_method att r ibutes = { 'foo' = > 'ba r ' } T r aces.t r ace('my_method', att r ibutes: att r ibutes) do supe r end end end MyClass.new.my_method -
> bundle exec bake t r aces:p r ovide r
:list output - - fo r mat json { "async": [ "t r aces/p r ovide r /async/ba r r ie r . r b", "t r aces/p r ovide r /async/task. r b", "t r aces/p r ovide r /async. r b" ], "async - pool": [ "t r aces/p r ovide r /async/pool/cont r olle r . r b" ], "p r otocol - http2": [ "t r aces/p r ovide r /p r otocol/http2/f r ame r . r b", "t r aces/p r ovide r /p r otocol/http2. r b" ] } -
# conf i g/t r aces. r b def p
r epa r e # Add HTTP/2 p r otocol t r aces: r equi r e "t r aces/p r ovide r /p r otocol/http2" end -
bundle add traces bundle add - - require false \
traces - backend - datadog -
bundle add - - require false \ traces - backend
- open_telemetry -
r equi r e 'met r ics' class MyClass def
self.my_method puts "Hello Wo r ld" end end Met r ics : : P r ovide r (MyClass.singleton_class) do CALL_COUNT = Met r ics.met r ic('call_count', :counte r ) def my_method CALL_COUNT.emit(1) supe r end end MyClass.my_method -
r equi r e 'met r ics' class MyClass def
self.my_method puts "Hello Wo r ld" end end Met r ics : : P r ovide r (MyClass.singleton_class) do CALL_COUNT = Met r ics.met r ic('call_count', :counte r ) def my_method CALL_COUNT.emit(1) supe r end end MyClass.my_method -
r equi r e 'met r ics' class MyClass def
self.my_method puts "Hello Wo r ld" end end Met r ics : : P r ovide r (MyClass.singleton_class) do CALL_COUNT = Met r ics.met r ic('call_count', :counte r ) def my_method CALL_COUNT.emit(1) supe r end end MyClass.my_method -
r equi r e 'met r ics' class MyClass def
self.my_method puts "Hello Wo r ld" end end Met r ics : : P r ovide r (MyClass.singleton_class) do CALL_COUNT = Met r ics.met r ic('call_count', :counte r ) def my_method CALL_COUNT.emit(1) supe r end end MyClass.my_method -
> bundle exec bake met r ics:p r ovide r
:list output - - fo r mat json { "async": [ "met r ics/p r ovide r /async/task. r b", "met r ics/p r ovide r /async. r b" ], "async - http": [ "met r ics/p r ovide r /async/http/client. r b", "met r ics/p r ovide r /async/http/se r ve r . r b", "met r ics/p r ovide r /async/http. r b" ], "async - containe r ": [ "met r ics/p r ovide r /async/containe r /gene r ic. r b", "met r ics/p r ovide r /async/containe r . r b" ] } -
# conf i g/met r ics. r b def p
r epa r e # Add HTTP client and se r ve r met r ics: r equi r e "met r ics/p r ovide r /async/http" end -
bundle add metrics bundle add - - require false \
metrics - backend - datadog -
Pro fi ler Traces Metrics Did something go wrong? Wh
a t f a iled? How did it f a il? More Det a il Less Det a il -
Bigger Overhe a d More D a t a Sm
a ller Overhe a d Less D a t a Pro fi ler Traces Metrics Did something go wrong? Wh a t f a iled? How did it f a il? More Det a il Less Det a il -
Console.info(self, "Hello Wo r ld", st r uctu r ed:
"data") Subject Mess a ge Structured D a t a -
r equi r e "console" Console.info(self, "Hello Wo r ld",
st r uctu r ed: "data") Console.debug(self, "Debugging info r mation", session: r equest.session) Console.wa r n(self, "This is a wa r ning") Console.e r r o r (self, "An e r r o r occu r r ed", exception: e r r o r ) Console.fatal(self, "A fatal e r r o r occu r r ed", exception: e r r o r ) -
# conf i g/console. r b def make_output(io = nil,
env = ENV, * * options) r equi r e "console/output/datadog" Console : : Output : : Datadog.new(supe r ) r escue LoadE r r o r supe r end -
23.18s info: p r ocess_action.action_cont r olle r : Incoming
r equest: GET "/". | { | "cont r olle r ": "WelcomeCont r olle r ", | "action": "index", | "fo r mat": "html", | "method": "GET", | "path": "/", | "status": 200, | "view_ r untime": 33.49500012397766, | "db_ r untime": 0.0, | "que r ies_count": 0, | "cached_que r ies_count": 0, | "sou r ce_add r ess": " : : 1", | "allocations": 60143, | "du r ation": 36.60800004005432 | } -
Summary Monitoring with Falcon ✅ Autom a tic he a
lth checks detect h a ngs a nd st a lls. -
Summary Monitoring with Falcon ✅ Autom a tic he a
lth checks detect h a ngs a nd st a lls. ✅ Supervisor fr a mework c a n monitor memory us a ge + custom monitors. -
Summary Monitoring with Falcon ✅ Autom a tic he a
lth checks detect h a ngs a nd st a lls. ✅ Supervisor fr a mework c a n monitor memory us a ge + custom monitors. ✅ Flexible a pplic a tion tr a cing + distributed tr a cing. -
Summary Monitoring with Falcon ✅ Autom a tic he a
lth checks detect h a ngs a nd st a lls. ✅ Supervisor fr a mework c a n monitor memory us a ge + custom monitors. ✅ Flexible a pplic a tion tr a cing + distributed tr a cing. ✅ Flexible a pplic a tion metrics. -
Summary Monitoring with Falcon ✅ Autom a tic he a
lth checks detect h a ngs a nd st a lls. ✅ Supervisor fr a mework c a n monitor memory us a ge + custom monitors. ✅ Flexible a pplic a tion tr a cing + distributed tr a cing. ✅ Flexible a pplic a tion metrics. ✅ Logging with tr a ce correl a tion a nd f lexible processing. -
Includes many of the things we talked about by default.
σϑΥϧτͰɺ͜Ε·Ͱʹͨ͠ଟ͘ͷ͜ͱΛؚΜͰ͍·͢ɻ -
> bundle exec bake agent:context:install Installed context f r om
17 gems: agent - context io - event met r ics t r aces async p r otocol - http p r otocol - http1 p r otocol - http2 async - se r vice bake - gem bake - r eleases cove r ed decode falcon sus sus - f i xtu r es - console utopia - p r oject -
Claude, consult agents.md and update my application to use falcon.
Claudeɺagents.mdΛࢀরͯ͠ɺΞϓϦέʔγϣϯΛFalconର Ԡʹߋ৽͍ͯͩ͘͠͞ɻ -
Let’s take Ruby to the next level with Async, Falcon
and Rails. AsyncɺFalconɺRailsͰRubyΛ࣍ͷϨϕϧɻ -
ͪ Ζ Μ Φ Ψ χ Ϋ ͳ ํ
๏ ͋ Γ · ͢