Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/fschuindt/tap_tempo
Limits the frequency that certain Elixir/BEAM functions can be called.
https://github.com/fschuindt/tap_tempo
Last synced: 3 days ago
JSON representation
Limits the frequency that certain Elixir/BEAM functions can be called.
- Host: GitHub
- URL: https://github.com/fschuindt/tap_tempo
- Owner: fschuindt
- License: mit
- Created: 2023-08-20T06:28:19.000Z (over 1 year ago)
- Default Branch: master
- Last Pushed: 2023-08-20T18:03:39.000Z (over 1 year ago)
- Last Synced: 2024-12-03T04:27:39.799Z (about 2 months ago)
- Language: Elixir
- Size: 13.7 KB
- Stars: 2
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# TapTempo
A concurrency-friendly, eager-evaluated, BEAM-wide function call rate limiter.
Adds virtual bottleneck to functions, so it respects a set of preconfigured limits.
## Installation
**Note:** This package isn't yet published to Hex.pm.
Add `:tap_tempo` to the list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:tap_tempo, "~> 0.1.0"}
]
end
```## About
It works based on two concepts, pools and queues.
Pools are configurable bottlenecks:
- `{:salesforce_api, max_executions_per_second: 50}`
- `{:stripe_api, max_executions_per_second: 10}`Each pool has one or more queues. Each queue represents a distinct priority within that pool:
```elixir
config :tap_tempo,
pools: [
{:salesforce_api, max_executions_per_second: 50}
],
queues: [
{:web, :salesforce_api, order: 1, timeout: 10_000},
{:background, :salesforce_api, order: 2, timeout: 30_000},
]
```- `order:` The order of priority for that queue.
- `timemout:` How long to wait for that call to respond in milliseconds.Usage:
```elixir
TapTempo.run(fn -> IO.puts("Hello world") end, :web)
TapTempo.run(fn -> IO.puts("Hello there") end, :background)
````TapTempo.run/2` returns whatever the given function returns, **or** `{:error, TapTempo.Response.t()}` when the timeout is reached before the function ever returned. Example: `{:error, %TapTempo.Response{type: :timeout, message: "TapTempo timed out after 30000 miliseconds for queue background on the salesforce_api pool."}}`.
If your system ever gets close to the configured limit, executions will experience an articial delay, just enough to keep it under. They will be evaluated following the chronological order of ingestion (FIFO), however, queues with lower `order` will always be put ahead.
As long as the system is under the limit, all executions are not only eagerly evaluated, but also concurrent:
```elixir
defmodule ConcurrencyExample do
def run do
spawn(fn ->
TapTempo.run(fn ->
:timer.sleep(1000)
IO.puts("Slow function")
end, :web)
end)spawn(fn ->
TapTempo.run(fn ->
IO.puts("Fast function")
end, :web)
end):ok
end
endConcurrencyExample.run()
# Fast function
# Slow function
```## ToDo
- [ ] Multiple pools. Some APIs have two different limits. (E.g. Per hour, per minute)
- [ ] Publish package.## License
This library is distributed as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).