A key-based debouncer with built-in implementations for Tesla and Req HTTP clients.

For HTTP requests, GET requests to the same URL are debounced, all other requests are unaffected. Debounced requests are rejected client-side and the HTTP request is not made.

Example

Tesla

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: ...}}

For full documentation, see Boing.TeslaMiddleware.

Req

iex(1)> client = Req.new() |> Boing.ReqPlugin.attach()
%Req.Request{...}
iex(2)> for _ <- 1..3, do: spawn(fn -> dbg(Req.get(client, url: "http://example.com")) end)
[#PID<0.208.0>, #PID<0.209.0>, #PID<0.210.0>]
Req.get(client, url: "http://example.com") #=> {:error, %Boing.ReqPlugin.DebouncedException{url: "http://example.com"}}
Req.get(client, url: "http://example.com") #=> {:error, %Boing.ReqPlugin.DebouncedException{url: "http://example.com"}}
Req.get(client, url: "http://example.com") #=> {:ok, %Req.Response{body: ...}}

For full documentation see Boing.ReqPlugin.

Direct

iex(1)> for i <- 1..3, do: spawn(fn -> IO.puts("Foo #{i}: #{inspect(Boing.debounce("foo"))}") end)
[#PID<0.221.0>, #PID<0.222.0>, #PID<0.223.0>]
iex(2)> for i <- 1..3, do: spawn(fn -> IO.puts("Bar #{i}: #{inspect(Boing.debounce("bar"))}") end)
[#PID<0.225.0>, #PID<0.226.0>, #PID<0.227.0>]
Bar 3: :ok
Foo 3: :ok
Bar 1: {:error, [debounced: "bar"]}
Foo 1: {:error, [debounced: "foo"]}
Foo 2: {:error, [debounced: "foo"]}
Bar 2: {:error, [debounced: "bar"]}

For full documentation see Boing.

Overview

Actions are debounced by assigning a key to related actions. For the Req and Tesla modules, the GET request URL is automatically used as the key. When the first action for that key occurs, a 1 second (by default, but configurable) timer is started. The timer is restarted for each subsequent request to the same key/URL that occurs before the timer expires. When the timer eventually expires, the most recent request is permitted, and the previous requests are debounced.

While this module includes support for Tesla and Req, the core logic is implementation-independent and can be used for any purpose.

For full documentation of the underlying implementation, see Boing.

Installation

Boing can be installed by adding it to your list of dependencies in mix.exs:

def deps do
  [
    {:boing, "~> 0.1.0"}
  ]
end

Documentation

Full documentation is available in iex via the h helper and also is published to Hex.