Skip to content
HomeConsoleGet started

Released versions of the runstate TypeScript and Python SDKs and what changed in each.

Both SDKs are published as runstate-sdk (npm and PyPI), MIT licensed, and versioned together.

npm install runstate-sdk
pip install runstate-sdk

These docs describe version 0.3.0. It works against the current hosted API (https://api.getrunstate.com).

0.3.0 replaces the whole SDK surface in both languages. You wrap a function once where you define it and call it as before; runstate does the coordination inside the call. There is no compatibility layer: the 0.2 names are gone, so upgrading means updating your code with the table below.

  • New surface: once, limit, take, slots, budget, queue (with send, gather and serve, and producer-only queues without a handler), setup, sleep, together, run, child, runId, stop, finish, context, events and status, on a default client (import runstate from 'runstate-sdk', import runstate) or a Runstate instance. See the TypeScript and Python references.
  • Runs are implicit. Every process joins the run named by RUNSTATE_RUN (default), or the one you name with runstate.run(name). You never pass run ids.
  • Default API address. The SDKs now connect to https://api.getrunstate.com unless RUNSTATE_BASE_URL says otherwise.
  • Durations are seconds, or strings such as '30s' and '10m'. Amounts are numbers or decimal strings.
  • Resources are declared in code. max, per and limit create a limit, slots or a budget the first time, and check the sizes after that.
  • Python: decorators work on plain and async def functions. Every module function has an a-prefixed async form (astop, atake, aserve, …), which replaces AsyncRunstate.
  • Errors: a smaller set of classes: ConfigError, AuthError, StoppedError, TimeoutError, OnceFailedError, TaskFailedError, BudgetExceededError, ResultTooLargeError, ConflictError, LeaseLostError and UnavailableError. Busy resources and rate limits are retried inside the SDK. See Errors & retries.
  • Removed: the TypeScript low-level client, the admin accessors for declaring resources (use setup() or the sizes on each wrapper), manual reservations and deliveries, run handles, task groups, timer and rendezvous handles, and diagnostics. The HTTP API still exposes everything for other languages and custom tooling.
0.2 0.3
const run = await new Runstate().scopes.create() nothing (runs are implicit) or runstate.run('name')
run.claim(k).run(fn) runstate.once(fn)(...args)
run.quota('q').take() runstate.take('q') or runstate.limit('q', fn)
run.pool('p').run(fn) runstate.slots('p', fn)
run.budget('b').reserve(...) + settle / void runstate.budget('b', fn, { reserve, cost })
bus.mailboxes.ensure + mailbox.submit + consume runstate.queue(name, handler), queue(input), runstate.serve()
run.groups.create(...) queue.gather(inputs, { need, accept })
run.timers.create(...).wait() runstate.sleep(name, duration)
run.barriers.create(...), arrive, wait runstate.together(name, count)
bus.events.watch runstate.events()
bus.diagnostics.run(id) runstate.status()
run.cancel() / run.complete() runstate.stop() / runstate.finish()

Python follows the same table with decorators: @runstate.once, @runstate.limit(...), @runstate.slots(...), @runstate.budget(...) and @runstate.queue(...).

  • Idle workers: consume() long-polls (waitMs / wait_ms, default 20 s), so an idle worker makes a few requests a minute instead of polling every pollMs. receive() and admit() accept a wait too. Empty waits and lease renewals don’t count toward the request rate.
  • Task groups: group.close() and expectedMembers / expected_members. An N_ACCEPTED group stays open until it is closed, reaches its expected members, or hits its deadline, and is only judged unreachable once closed. seal() is deprecated in favour of close().
  • Runs: scopes.create({ name }) and child({ name }) store the name and return it in reads.
  • Admission: TypeScript TaskRequirements accepts budgets and admit() returns reservations; Python exports TaskRequirements, UnitsRequirement and BudgetRequirement type hints. Pool units and the work-limit slot taken by admit() are released when the task completes, is rejected or is retried (a server change; no SDK call needed).
  • Permissions: declaring a pool, quota, work limit or budget that already exists with matching sizes works with a key that may not create resources. FORBIDDEN is raised only when the resource does not exist.
  • Python: MailboxRef.receive() works. In 0.1.0 it raised TypeError on every call; consume() was not affected.
  • Both SDKs: waiting claim and pool acquisitions (acquire({ wait: true }), run()) now also wait through CONCURRENCY_LIMITED, retrying about once a second.
  • Both SDKs: CONCURRENCY_LIMITED and OPERATIONS_EXHAUSTED map to RateLimitError.
  • TypeScript low-level client: error codes are no longer collapsed to UNAVAILABLE when the code was added to the contract after the client was written (for example INSUFFICIENT_BUDGET).

First public release of both SDKs: runs, claims, work queues and durable tasks, task groups, concurrency pools, shared quotas, work limits, budgets, barriers, timers, events and diagnostics; AsyncRunstate and the blocking Runstate client in Python; the low-level createRunstateClient in TypeScript.