I maintain a side project called Airfield Directory, a Rails app backed by DynamoDB for general aviation pilots.
Because DynamoDB access is essentially all network I/O over HTTPS, it is a good playground to tinker with Ruby fibers before bringing the same approach into other production systems.
Airfield Directory runs on Falcon because I want fiber-based concurrency without the memory overhead of thread-per-request. It should feel fast and smooth under load.
Then the dynamic map happened.
The map view fans out a lot of DynamoDB queries across H3 hexagonal grid cells (a system invented by Uber). Under Falcon, I expected those requests to overlap in fibers. Instead, the reactor stalled and the app behaved like it was single-threaded again: latency spikes, janky scrolling, that “it’s fast until it isn’t” feel.
My first instinct was to do what I do elsewhere (e.g. ruby_llm): wrap the hot
path in Async { ... } and trust the scheduler. It didn’t help. The AWS SDK was
still blocking the reactor.
I eventually fell back to threads just to keep the UI responsive. It worked, but it felt wrong.
The AWS SDK’s default HTTP transport uses Net::HTTP wrapped in a connection pool. Contrary to what you might expect, Net::HTTP itself is fiber-friendly in Ruby 3.0+—the fiber scheduler hooks into blocking I/O and yields to other fibers automatically.
The problem is that the SDK’s Net::HTTP transport is synchronous end-to-end and
relies on implicit scheduler hooks in Net::HTTP, OpenSSL, and DNS resolution.
Ruby 3+ Mutex is fiber-aware, and the SDK’s pool mutex only guards
checkout/check-in—not the request itself. But in practice, those implicit hooks
don’t yield reliably, so the single reactor thread gets blocked often enough
that all fibers serialize.
I dug through the SDK internals and landed on the same conclusion captured in this issue: https://github.com/aws/aws-sdk-ruby/issues/2621 and an abandoned experimental repo.
What we observed:
Async::Barrier serialized under Falcon.async-http fixed it—because async-http is
fiber-native end-to-end (pool + I/O), so the reactor can actually interleave
requests.I built a new HTTP handler gem plugin for aws-sdk-core using async-http called aws-sdk-http-async. It aims to preserve the SDK’s semantics (retries, error handling, telemetry, content-length validation), but make the transport fiber-friendly under Falcon.
Key goals:
Add it to your Gemfile:
gem 'aws-sdk-http-async'
More information in the repo on Github