Boing is a small package that provides the ability to debounce HTTP requests, with implementations included for Tesla
and Req
.
Example for Tesla from the README:
iex(1)> client = Tesla.client([Boing.TeslaMiddleware])
%Tesla.Client{...}
iex(2)> for _ <- 1..3, do: spawn(fn -> dbg(Tesla.get(client, "http://example.com")) end)
[#PID<0.208.0>, #PID<0.209.0>, #PID<0.210.0>]
Tesla.get(client, "http://example.com") #=> {:error, [debounced: "http://example.com"]}
Tesla.get(client, "http://example.com") #=> {:error, [debounced: "http://example.com"]}
Tesla.get(client, "http://example.com") #=> {:ok, %Tesla.Env{body: ...}}
This initial version only debounces GET requests. It also exposes the debouncer that can be used to integrate with other HTTP clients or any other application.
The debouncer is implemented using Registry
, DynamicSupervisor
, and :gen_statem
. I’m hoping that relying on standard components helps keep this implementation performant, but feedback and suggestions for potential improvements are also welcome.
My motivation:
I have a project that handles webhook events concurrently, where many events are for the same remote resource. The event handlers for those resources result in many identical API requests being made against the remote service. I found that debouncing the identical requests, allowing only the latest one to go through (and the other event handlers to terminate), was an effective way to reduce redundant usage of the remote API.