one_flight should stay small: the core package is a request-coalescing primitive,
not a cache, HTTP client, retry library, or JSON library. Integrations should be
added only when they make the primitive easier to apply without weakening that
boundary.
v0.1: Single-node core
Status: implemented.
- Single-node
OneFlight.run/3andOneFlight.run!/3. OneFlight.async/3andOneFlight.await/2.OneFlight.forget/2.OneFlight.stats/2.- Supervised Task execution.
- Per-waiter timeouts.
- Demand-driven cancellation.
- Execution error capture for raise, exit, and throw.
- Telemetry events for collapsed work.
v0.2: Cluster scope
Goal: keep the same call-site API while coalescing duplicate calls across a connected Elixir cluster.
- Add
scope: :cluster. - Use the two-level design:
- level 1: local singleflight per node
- level 2: only local leaders enter cluster coordination
- Use
:globalname registration for level-2 coordination. - Keep closures local; user functions never cross the wire.
- Add
:peertests for simultaneous candidates, leader-node death, and netsplit behavior. - Document the honest guarantee: at most one execution per connected partition in steady state, with duplicate windows during membership changes.
v0.3: Req integration
Goal: make outbound HTTP request coalescing ergonomic for projects that already use Req.
Likely shape:
Req.new()
|> OneFlight.Req.attach(name: MyApp.Flights, key: :url)
|> Req.get!(url: url)Use cases:
- duplicate GET requests to the same upstream resource
- rate-limited APIs
- remote configuration fetches
- token introspection
- service discovery endpoints
The integration should let callers choose the key strategy, such as URL only, method plus URL, or method plus URL plus request body hash.
v0.4: Finch examples or helper
Goal: support lower-level HTTP users without forcing a Req dependency.
Start with README examples:
OneFlight.run({:http, :get, url, headers_hash}, fn ->
Finch.build(:get, url, headers)
|> Finch.request(MyFinch)
end, name: MyApp.Flights)Only add a dedicated helper if real users ask for it. A OneFlight.Finch module
is less obviously valuable than a Req step because Finch intentionally has a small
low-level API.
Poison and JSON workloads
Poison is a use case, not an integration target.
Good uses:
- coalesce loading and decoding the same large remote JSON config
- avoid duplicate parse work after a cache miss
- dedupe expensive schema/source transformations keyed by content hash
Avoid a OneFlight.Poison module unless a concrete repeated pattern appears.
JSON libraries are easy to wrap with OneFlight.run/3 directly.
Possible later work
strategy: :ringfor large clusters where:globalcoordination becomes a measured bottleneck.OneFlight.Reqrequest-key presets for common safe cases.- Markdown report or telemetry example snippets for observability docs.
- Benchmarks comparing duplicate uncoalesced work vs
one_flightunder hot keys.
Explicit non-plans
- No result TTL.
- No persistent storage.
- No retry, backoff, or circuit breaking.
- No cache API.
- No distributed consensus dependency.