Shelly.RateGate (Shelly v0.1.0)

Copy Markdown View Source

Per-account rate gate for Shelly Cloud traffic. The cloud allows ~1 request/second/account and returns 429 for anything faster — and polling, control commands and one-off calls all draw from the same budget, so every call should flow through one gate.

Callers reserve the next free slot for their key and sleep in their own process until it arrives; the gate itself never blocks. When the backlog for a key exceeds one minute, callers are rejected with {:error, :throttled} instead of being queued into a burst:

Shelly.RateGate.run({server, auth_key}, fn -> Req.request(...) end)

Start it in your supervision tree:

children = [Shelly.RateGate, ...]

When the gate isn't running (scripts, tests), calls pass straight through unpaced.

Summary

Functions

Returns a specification to start this module under a supervisor.

Run fun in the calling process, no earlier than the key's next free slot. key is any term identifying the budget (typically {server, auth_key} or an account id).

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

run(key, fun, gate \\ __MODULE__)

@spec run(term(), (-> result), GenServer.server()) :: result | {:error, :throttled}
when result: var

Run fun in the calling process, no earlier than the key's next free slot. key is any term identifying the budget (typically {server, auth_key} or an account id).

Returns fun's result, or {:error, :throttled} when the key's backlog already exceeds one minute.

start_link(opts \\ [])