@@ -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 } }
100106end
0 commit comments