The limiter slot's methods

Part of the adapter protocol, version 2 (an addition within it; no version of its own).

A limiter module keeps a host's calls to modules and models inside the providers' limits. The host asks it before every call, and holds the call until it is granted. lf ships one, @lf/memory-limiter (the default), which keeps the limits in lf's own process. A limiter shared by many hosts (Redis, a database) is a third-party module lf starts (or reaches at its URL) and calls over adapter protocol 2.

The engine knows nothing of limits. Only the host asks.

What one acquire counts #

Installing one #

A folder in the project's externals folder, with an lf-external.yaml:

name: acme_limits
kind: core
slot: limiter
command: [node, limiter.mjs]   # started in this folder
settings:                      # optional; prompted by `lf connect acme_limits`
  - { name: url, label: the Redis URL, secret: true }

The envelope #

The store slot's envelope (store-slot.md): adapter protocol 2's HTTP, one request at a time. Instants are Date.toISOString strings.

Methods #

No method waits. A refusal says when to ask again; the host does the waiting.

methodparamsresult
limiter.open{ settings: { [name]: string } }null
limiter.acquire{ key, cost, limits: [{ key, calls?, perMs?, concurrent? }], holdMs }{ granted: true, permit }, or { granted: false, retryAt }
limiter.release{ permit }null; a permit released twice, or never given, changes nothing
limiter.throttle{ key, until }null

The contract suite #

undefined holds every limiter to the same cases. apps/cli runs it over lf --contract-limiter (lf's built-in) and lf --contract-limiter-slot (a test module filling a project's slot, apps/cli/src/__test__/limiter_module/serve.ts), in limiter_contract.test.ts. The platform's built-in passes the same cases in services/limiter/__test__.

Changes #