Skip to content

Commit d072ec4

Browse files
committed
Move capacity and refill to config
1 parent 5ec9781 commit d072ec4

File tree

5 files changed

+46
-26
lines changed

5 files changed

+46
-26
lines changed

.iex.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
if Code.loaded?(Ecto.Query) do
2-
Kernel.SpecialForms.import(Ecto.Query)
2+
import Ecto.Query
33
end
44

55
alias Lightning.Repo

config/config.exs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ config :lightning, LightningWeb.Endpoint,
2525
pubsub_server: Lightning.PubSub,
2626
live_view: [signing_salt: "EfrmuOUr"]
2727

28+
config :lightning, Lightning.WebhookRateLimiter,
29+
start: false,
30+
capacity: 10,
31+
refill_per_second: 2
32+
2833
config :lightning, Lightning.Extensions,
2934
rate_limiter: Lightning.Extensions.RateLimiter,
3035
usage_limiter: Lightning.Extensions.UsageLimiter,

config/test.exs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ config :lightning, LightningWeb.Endpoint,
5353
"/8zedVJLxvmGGFoRExE3e870g7CGZZQ1Vq11A5MbQGPKOpK57MahVsPW6Wkkv61n",
5454
server: true
5555

56+
config :lightning, Lightning.WebhookRateLimiter, start: true
57+
5658
config :lightning, Lightning.Runtime.RuntimeManager,
5759
ws_url: "ws://localhost:4002/worker"
5860

lib/lightning/application.ex

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ defmodule Lightning.Application do
77

88
require Logger
99

10+
@rate_limiter_opts Application.compile_env!(
11+
:lightning,
12+
Lightning.WebhookRateLimiter
13+
)
14+
1015
@impl true
1116
def start(_type, _args) do
1217
# Initialize ETS table for adapter lookup
@@ -181,10 +186,12 @@ defmodule Lightning.Application do
181186
end
182187

183188
def start_phase(:init_rate_limiter, :normal, _args) do
184-
Horde.DynamicSupervisor.start_child(
185-
Lightning.DistributedSupervisor,
186-
Lightning.WebhookRateLimiter
187-
)
189+
if @rate_limiter_opts[:start] do
190+
Horde.DynamicSupervisor.start_child(
191+
Lightning.DistributedSupervisor,
192+
{Lightning.WebhookRateLimiter, @rate_limiter_opts}
193+
)
194+
end
188195

189196
:ok
190197
end

lib/lightning/webhook_rate_limiter.ex

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ defmodule Lightning.WebhookRateLimiter do
22
@moduledoc false
33
use GenServer
44

5-
@capacity 10
6-
@refill_per_sec 2
7-
85
require Logger
96

107
def child_spec(opts) do
@@ -17,31 +14,36 @@ defmodule Lightning.WebhookRateLimiter do
1714

1815
%{
1916
id: id,
20-
start: {__MODULE__, :start_link, [name]},
17+
start: {__MODULE__, :start_link, [Keyword.put(opts, :name, name)]},
2118
shutdown: 10_000,
2219
restart: :transient
2320
}
2421
end
2522

26-
def start_link(name) do
23+
def start_link(opts) do
24+
name = Keyword.fetch!(opts, :name)
25+
2726
with {:error, {:already_started, pid}} <-
28-
GenServer.start_link(__MODULE__, [], name: via_tuple(name)) do
27+
GenServer.start_link(__MODULE__, opts, name: via_tuple(name)) do
2928
Logger.info("already started at #{inspect(pid)}, returning :ignore")
3029
:ignore
3130
end
3231
end
3332

3433
@impl true
35-
def init([]) do
34+
def init(opts) do
3635
Process.flag(:trap_exit, true)
3736

38-
{:ok, %{table: :ets.new(:table, [:set])}}
37+
capacity = Keyword.fetch!(opts, :capacity)
38+
refill = Keyword.fetch!(opts, :refill_per_second)
39+
40+
{:ok, %{table: :ets.new(:table, [:set]), capacity: capacity, refill_per_second: refill}}
3941
end
4042

41-
def check_rate(bucket, cost \\ 1, name \\ __MODULE__) do
43+
def check_rate(bucket, capacity \\ nil, refill \\ nil, name \\ __MODULE__) do
4244
name
4345
|> via_tuple()
44-
|> GenServer.call({:check_rate, bucket, cost})
46+
|> GenServer.call({:check_rate, bucket, capacity, refill})
4547
end
4648

4749
def inspect_table(name \\ __MODULE__) do
@@ -51,8 +53,8 @@ defmodule Lightning.WebhookRateLimiter do
5153
end
5254

5355
@impl true
54-
def handle_call({:check_rate, bucket, cost}, _from, %{table: table} = state) do
55-
{:reply, do_check_rate(table, bucket, cost), state}
56+
def handle_call({:check_rate, bucket, capacity, refill}, _from, state) do
57+
{:reply, do_check_rate(state, bucket, capacity, refill), state}
5658
end
5759

5860
@impl true
@@ -72,17 +74,24 @@ defmodule Lightning.WebhookRateLimiter do
7274
{:stop, :normal, state}
7375
end
7476

75-
def do_check_rate(table, bucket, cost) do
77+
def do_check_rate(
78+
%{table: table} = config,
79+
bucket,
80+
capacity,
81+
refill_per_sec
82+
) do
7683
now = System.monotonic_time(:millisecond)
84+
capacity = capacity || config[:capacity]
85+
refill_per_sec = refill_per_sec || config[:refill_per_second]
7786

78-
:ets.insert_new(table, {bucket, {@capacity, now}})
87+
:ets.insert_new(table, {bucket, {capacity, now}})
7988
[{^bucket, {level, updated}}] = :ets.lookup(table, bucket)
8089

81-
refilled = div(now - updated, 1_000) * @refill_per_sec
82-
current = min(@capacity, level + refilled)
90+
refilled = div(now - updated, 1_000) * refill_per_sec
91+
current = min(capacity, level + refilled)
8392

84-
if current >= cost do
85-
level = current - cost
93+
if current >= 1 do
94+
level = current - 1
8695
:ets.insert(table, {bucket, {level, now}})
8796

8897
{:allow, level}
@@ -92,9 +101,6 @@ defmodule Lightning.WebhookRateLimiter do
92101
end
93102
end
94103

95-
def capacity, do: @capacity
96-
def refill_per_second, do: @refill_per_sec
97-
98104
def via_tuple(name),
99105
do: {:via, Horde.Registry, {Lightning.HordeRegistry, name}}
100106
end

0 commit comments

Comments
 (0)