Skip to content

Instantly share code, notes, and snippets.

@maxneuvians
Last active June 11, 2023 04:07
Show Gist options
  • Save maxneuvians/47fb561a635396ae03b00007a989dd72 to your computer and use it in GitHub Desktop.
Save maxneuvians/47fb561a635396ae03b00007a989dd72 to your computer and use it in GitHub Desktop.
Leaky Bucket GenServer in Elixir
defmodule LeakyBucket.Bucket do
@moduledoc """
Simulates a leaky bucket implementation
"""
use GenServer
@initial_amount 0
@increment_rate 1
@leak_rate 2
@leak_interval 500
@size 40
# Public
@doc """
Increments the amount of water in the bucket
"""
def increment do
GenServer.call(__MODULE__, :increment)
end
# Private
@doc """
Starts Bucket with initial amount
"""
def start_link() do
GenServer.start_link(__MODULE__, %{count: @initial_amount}, [name: __MODULE__])
end
@doc """
Initiates the leak counter
"""
def init(state) do
send self(), :leak
{:ok, state}
end
@doc """
Returns an error because bucket will be too full
"""
def handle_call(:increment, _from, %{count: count}) when (count + @increment_rate) > @size do
{:reply, :too_many_requests, %{count: count}}
end
@doc """
Increments the amount of water in the bucket
"""
def handle_call(:increment, _from, %{count: count}) do
{:reply, count + @increment_rate, %{count: count + @increment_rate}}
end
@doc """
Set count to 0 if count is less than leak rate
"""
def handle_info(:leak, %{count: count}) when count < @leak_rate do
Process.send_after(self(), :leak, @leak_interval)
{:noreply, %{count: 0}}
end
@doc """
Leak amount from bucket
"""
def handle_info(:leak, %{count: count}) do
Process.send_after(self(), :leak, @leak_interval)
{:noreply, %{count: count - @leak_rate}}
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment