lim
Deadlines, timeouts, and retry - sleep for milliseconds, get current epoch-ms time, check if a deadline has passed, check if a budget is exhausted, compute remaining time, assert deadline not passed, compute an absolute deadline, execute a thunk within a budget, compute linear and exponential backoff delays, retry a thunk with backoff, guard loop iterations against runaway, and busy-wait for a predicate to become true.
Load with: use lim
What this module does
lim provides all the timing primitives needed to write
timeout-aware, resilient code. It operates in milliseconds throughout.
The deadline pattern is: compute a deadline with limad, then
periodically check with limdp or assert with limxd.
The retry pattern uses limry with either limbl
(linear) or limbx (exponential) backoff delays.
Quick example
use lim
# Sleep
limsl(500) # sleep 500ms
# Deadline
dl = limad(5000) # 5 seconds from now
limxd(dl, "timed out") # error if past
# Budget check
t0 = limno()
# ... do work ...
prn(limrm(t0, 2000)) # ms remaining
# Retry with linear backoff
r = limry(5, 100, 1000, \() http.get("https://api.example.com"))
# retries up to 5 times, sleeping 100ms, 200ms, 300ms... capped at 1000ms
# Wait until predicate is true (or deadline passes)
dl2 = limad(10000)
ok = limwa(dl2, \() queue_ready())
Functions
Time primitives
limno() / lim.now()Returns current time in milliseconds since epoch.
limsl(ms) / lim.sleep(ms)Sleeps for ms milliseconds.
Deadlines and budgets
limad(budget_ms) / lim.deadline(budget_ms)Returns an absolute deadline: now + budget_ms.
limdp(deadline_ms) / lim.past(deadline_ms)Returns tru if the wall clock is past deadline_ms.
limaf(t0_ms, budget_ms) / lim.after(t0, budget)Returns tru if now - t0 > budget.
limrm(t0_ms, budget_ms) / lim.remaining(t0, budget)Returns milliseconds remaining in the budget, or 0 if exhausted.
limxd(deadline_ms, msg) / lim.check(deadline, msg)Throws msg (default: "lim: deadline") if the deadline has passed. No-op otherwise.
limwi(t0, budget, thunk, msg) / lim.within(t0, budget, fn)Throws if the budget is exhausted, otherwise calls thunk().
limgu(i, max, msg) / lim.guard(i, max)Throws if loop counter i >= max. Protects against runaway loops.
Backoff and retry
limbl(attempt, base_ms, cap_ms) / lim.backoff(n, base, cap)Computes a linear backoff delay: base * (attempt + 1), capped at cap_ms.
limbx(attempt, base_ms, cap_ms) / lim.exp_backoff(n, base, cap)Computes exponential backoff (doubling each attempt) capped at cap_ms, then sleeps for that duration.
limry(max, base_ms, cap_ms, thunk) / lim.retry(n, base, cap, fn)Calls thunk() up to max times. Stops on success (thunk returns an object with no err field). Sleeps with linear backoff between attempts. Returns the last result.
Waiting
limwa(deadline_ms, pred) / lim.wait(deadline, fn)Busy-waits (sleeping 1ms between polls) until pred() returns truthy or the deadline passes. Returns tru if predicate was satisfied, fls if timed out.
Notes
- No stdlib dependencies - uses
__sys_sleep_msand__sys_time_msdirectly.