2.2.0
Concurrency keys: limit runs per customer, not per job
A concurrency limit can now apply per key, so one busy customer can no longer hold up everyone else's runs.
- New
- Fixed
Concurrency keys
Until now a concurrency limit applied to a whole job: limit: 20 meant 20 runs at once, across all your customers. When one customer imported 50,000 contacts, everyone else’s imports waited behind them.
A limit can now take a key. Runnel keeps a separate count for each key value, so the limit below allows 2 runs at a time per account and any number of accounts at once.
export const importContacts = runnel.job({
name: 'import-contacts',
concurrency: { limit: 2, key: (p) => p.accountId },
run: async (payload: { accountId: string; fileId: string }, ctx) => { /* … */ },
});Python takes concurrency=Concurrency(limit=2, key=lambda p: p["account_id"]), and Go runnel.WithConcurrencyKey(2, fn). Runs waiting for a slot show as queued with the reason “Waiting for concurrency key acc_42” in the dashboard.
Keys are free on every plan. A job can have up to 100,000 active keys.
Fixes
- A run cancelled while its attempt was starting could be marked
runningfor up to a minute. runnel devnow reloads whenrunnel.config.tschanges, not only when job files do.- Fixed a memory leak in the TypeScript worker when a job logged objects with circular references.