Butler — a Ruby HTTP client designed around modern Fiber-based concurrency

HTTP/1.1 and HTTP/2 with transparent ALPN negotiation, structured concurrency, built-in resilience, and security-conscious defaults — without ever exposing its transport in the public API.

Butler owns its own public API — Client, Request, Response, Headers — built around Ruby's Fiber::Scheduler rather than one Thread per in-flight request. That's the whole point of the design: real HTTP/2 multiplexing, structured concurrency you can actually reason about (client.async { |tasks| ... }), and a resilience layer (timeouts, deadlines, retries with backoff+jitter, a circuit breaker) that's part of the client, not four extra gems bolted onto Net::HTTP.

gem install butler-http
# HTTParty-style, zero setup:
Butler.get("https://api.example.com/users").json

# Or a configured Client, for connection pooling/retries/middleware tuned per-API:
client = Butler::Client.new(base_url: "https://api.example.com")

client.async do |tasks|
  users  = tasks.async { client.get("/users") }
  orders = tasks.async { client.get("/orders") }
  { users: users.wait.json, orders: orders.wait.json }
end

What it does

How it compares

CapabilityButlerFaradayExconNet::HTTP
Fiber-native concurrencylimited
HTTP/2 (ALPN, multiplexed)✓ (first-class)adapter-dependentlimiteddepends
Connection poolingadaptermanual
Retries + backoff/jitterbuilt-inmiddlewarelimitedmanual
Circuit breakerbuilt-inexternal gemexternal gemexternal gem
Deadlines (total budget across retries)
OpenTelemetryfirst-class, optionalexternalexternalexternal
Native request stubbingvia WebMockvia WebMockvia WebMock

The one architectural rule that keeps this from rotting into "Faraday but slower": Butler owns its public abstractions. async/async-http implement the real transport underneath, but nothing outside lib/butler/transport.rb ever touches those types — the public API doesn't change if the transport underneath it ever does. Full breakdown, including Excon/HTTParty and a real Sequential/Concurrent benchmark matrix, in the README.

Guides

Links