Description
The Rate Limiter with Token Bucket algorithm
This is a fork of ExRated, but with some changes:
- the checkout and inspection always return the same result tuple
- asynchronous counterparts for checkout, inspect and delete
- configuration can be given on initialization and not only via application environment (useful when starting multiple rate limiters with different settings)
Ralitobu alternatives and similar packages
Based on the "Miscellaneous" category.
Alternatively, view Ralitobu alternatives based on common mentions on social networks and blogs.
-
ex_rated
ExRated, the Elixir OTP GenServer with the naughty name that allows you to rate-limit calls to any service that requires it. -
gen_task
Generic Task behavior that helps encapsulate errors and recover from them in classic GenStage workers. -
countriex
All sorts of useful information about every country. A pure elixir port of the ruby Countries gem
CodeRabbit: AI Code Reviews for Developers
Do you think we are missing an alternative of Ralitobu or a related project?
README
Ralitobu
The Rate Limiter with Token Bucket algorithm
This is a fork of ExRated, but with some changes:
- the checkout and inspection always return the same result tuple
- asynchronous counterparts for checkout, inspect and delete
- configuration can be given on initialization and not only via application environment (useful when starting multiple rate limiters with different settings)
Installation
In mix.exs
:
def deps do
[{:ralitobu, "~> 0.1.0"}]
end
def application do
[applications: [:ralitobu]]
end
Usage
Checkouts
Ralitobu.checkout/3
(Ralitobu.checkout(id, limit, lifetime)
using default server)Ralitobu.checkout/4
(Ralitobu.checkout(server, id, limit, lifetime)
)
The result tuple format:
{success, counter, remaining_limit, total_limit, countdown, created_at, updated_at}
# 1st call:
Ralitobu.checkout("my-bucket", 3, 10_000)
#=> {:ok, 1, 2, 3, 7806, 1461432862194, 1461432862194}
# 3rd call:
Ralitobu.checkout("my-bucket", 3, 10_000)
#=> {:ok, 3, 0, 3, 7799, 1461432862194, 1461432862201}
# 4th call fails (over rate limit):
Ralitobu.checkout("my-bucket", 3, 10_000)
#=> {:error, 3, 0, 3, 7795, 1461432862194, 1461432862200}
Inspection
Ralitobu.inspect/3
(Ralitobu.inspect(id, limit, lifetime)
using default server)Ralitobu.inspect/4
(Ralitobu.inspect(server, id, limit, lifetime)
)
The result tuple format:
{success, counter, remaining_limit, total_limit, countdown, created_at, updated_at}
# multiple calls do not increment the counter:
Ralitobu.inspect("my-bucket", 3, 10_000)
#=> {:ok, 2, 3, 3, 4132, 1461432862194, 1461432862200}
Ralitobu.inspect("my-bucket", 3, 10_000)
#=> {:ok, 2, 3, 3, 4130, 1461432862194, 1461432862200}
# bucket does not exists:
Ralitobu.inspect("my-other-bucket", 3, 10_000)
#=> {:ok, 0, 3, 3, 9142, nil, nil}
Deletion
Ralitobu.delete/1
(Ralitobu.delete(id)
using default server)Ralitobu.delete/2
(Ralitobu.delete(server, id)
)
Result is either :ok
or :error
, depending if the bucket existed or not.
# bucket (still) exists:
Ralitobu.delete("my-bucket")
#=> :ok
# bucket is not present (anymore):
Ralitobu.delete("my-bucket")
#=> :error
New server instance
The application always starts a default server, but you can run your own instance(s) as well.
Ralitobu.start_server/2
(Ralitobu.start_server(configuration, gen_server_opts)
)
{:ok, server} = Ralitobu.start_server(
[table_name: :another_ralitobu_table, timeout: 30_000_000, cleanup_rate: 15_000],
[name: :another_ralitobu_server]
)
You must provide the name
parameter for the GenServer options,
otherwise it will take the default name and therefore not starting a new server.
Also the table_name
must be different, too.
Server configuration
table_name
(atom): The name of the ETS tabletimeout
(integer): milliseconds; buckets older than (now - timeout) will be cleaned up (based on last update timestamp)cleanup_rate
(integer): milliseconds; the interval for the clean up task