Skip to content

johnknott/debounce-and-throttle

Repository files navigation

DebounceAndThrottle

Hex version badge License Code coverage badge Github Workflow

DebounceAndThrottle is a simple library to allow to debounce or throttle function calls or message sending.

The following page explains throttling and debouncing quite well, albeit from a javascript perspective.

[https://css-tricks.com/debouncing-throttling-explained-examples/]

Examples can be found below and full documentation can be found at hexdocs.pm.

Installation

The package can be installed by adding debounce_and_throttle to your list of dependencies in mix.exs:

def deps do
  [
    {:debounce_and_throttle, "~> 0.9.0"}
  ]
end

Setup

Setup with a Supervision Tree, perhaps in a Phoenix project

Add DebounceAndThrottle.Server to your Supervision tree in lib/<application_name>/application.ex

children = [DebounceAndThrottle.Server, ...]

Setup without a Supervision Tree, perhaps in a standalone script

DebounceAndThrottle.Server.start_link([])

Usage

Alias Debounce and Throttle if you want to keep things terse.

alias DebounceAndThrottle.{Debounce, Throttle}

Debounce

This anonymous function will be called after 5 seconds, but only if this method wasnt called in the interim with the same key

Debounce.call(fn -> IO.puts("Hey there!") end, "some-key", 5_000)

This module, function and arguments will be called after 5 seconds, but only if this method wasnt called in the interim with the same key

Debounce.apply(IO, :puts, ["Hey there!"], "some-key", 5_000)

This message will be sent after 5 seconds, but only if this method wasnt called in the interim with the same key

Debounce.send(self(), :some_message, "some-key", 5_000)

Returns the state - the current list of debounced functions. Useful for debugging.

iex> Debounce.state
%{
  apply: %{},
  call: %{
    "say_hey" => %DebounceAndThrottle.Debounce{
      debounced_count: 1,
      extra_data: %{fun: 'Function<45.65746770/0 in :erl_eval.expr/5>'},
      scheduled_at: ~U[2022-03-12 22:50:01.190171Z],
      timer_ref: 'Reference<0.418177534.3850108929.259344>'
    }
  },
  send: %{}
}

Throttle

This anonymous function will be called straight away, but only if this method wasnt called in the last 5 seconds with the same key

Throttle.call(fn -> IO.puts("Hey there!") end, "some-key", 5_000)

This module, function and arguments will be called straight away, but only if this method wasnt called in last 5 seconds with the same key

Throttle.apply(IO, :puts, ["Hey there!"], "some-key", 5_000)

This message will be sent straight away, but only if this method wasnt called in the last 5 seconds with the same key

Throttle.send(self(), :some_message, "some-key", 5_000)

Returns the state - the current list of throttled functions. Useful for debugging.

iex> Throttle.state
%{
  apply: %{},
  call: %{
    "say_hey" => %DebounceAndThrottle.Throttle{
      extra_data: %{fun: 'Function<45.65746770/0 in :erl_eval.expr/5>'},
      status: :executed,
      throttled_count: 0,
      throttled_until: -576460730743,
      throttled_until_utc: ~U[2022-03-12 22:47:39.829107Z]
    }
    ...
  },
  send: %{}
}

Notes

Choice of key

Your choice of what to use as the key depends on the granularity you want to throttle or debounce things.

So, bad example - if you wanted to throttle a send_sms function - if you used send_sms as the key it would throttle the function for every user in the system which is probably not what you want. So you might use something like sms-#{user_id} as the key to throttle it per user.

License

This project is licensed under the MIT License - see the LICENSE.md file for details

About

Debounce and Throttle helpers for Elixir.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages