summaryrefslogtreecommitdiff
path: root/lib/limiter.ex
diff options
context:
space:
mode:
Diffstat (limited to 'lib/limiter.ex')
-rw-r--r--lib/limiter.ex47
1 files changed, 47 insertions, 0 deletions
diff --git a/lib/limiter.ex b/lib/limiter.ex
new file mode 100644
index 0000000..84c601c
--- /dev/null
+++ b/lib/limiter.ex
@@ -0,0 +1,47 @@
+defmodule Limiter do
+ @ets __MODULE__.ETS
+
+ def new(name, max_running, max_waiting) do
+ name = atom_name(name)
+ :persistent_term.put(name, {max_running, max_waiting})
+ :ets.new(name, [:public, :named_table])
+ :ok
+ end
+
+ def limit(name, fun) do
+ {max_running, max_waiting} = :persistent_term.get(atom_name(name))
+ max = max_running + max_waiting
+ counter = inc(name)
+
+ cond do
+ counter <= max_running ->
+ fun.()
+
+ counter > max ->
+ {:error, :overload}
+
+ counter > max_running ->
+ wait(name, fun)
+ end
+ after
+ dec(name)
+ end
+
+ defp wait(name, fun) do
+ Process.sleep(150)
+ dec(name)
+ limit(name, fun)
+ end
+
+ defp inc(name) do
+ name = atom_name(name)
+ :ets.update_counter(name, name, {2, 1}, {name, 0})
+ end
+
+ def dec(name) do
+ name = atom_name(name)
+ :ets.update_counter(name, name, {2, -1}, {name, 0})
+ end
+
+ defp atom_name(suffix), do: Module.concat(@ets, suffix)
+end