Last active
July 9, 2025 00:20
-
-
Save aod/2974df1938e21c268166ba2c19f80d29 to your computer and use it in GitHub Desktop.
Simple KV backoff with Deno
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // const voidFn = (...args: unknown[]) => void args | |
| const log = console.log /* voidFn */; | |
| export async function expensive() { | |
| const kv = await Deno.openKv(); | |
| const now = `[${performance.now()}]`; | |
| const key = ["namespace", "expensive"]; | |
| const cache = await kv.get(key); | |
| log(`${now} kv.get(${key}) = ${cache.value}`); | |
| if (cache.value) { | |
| log(`${now} πΆ found!`); | |
| return cache.value; | |
| } | |
| if (!(await acquireLock(key))) { | |
| log(`${now} π backing off!`); | |
| return backoff(kv, key); | |
| } | |
| log(`${now} π₯΅ working!`); | |
| await sleep(1000); | |
| const data = Math.random(); | |
| await kv.set(key, data, { expireIn: 1000 * 5}); | |
| log(`${now} π done!`); | |
| await releaseLock(key); | |
| log(`${now} π released lock!`); | |
| return data; | |
| } | |
| async function acquireLock(key: Deno.KvKey) { | |
| const kv = await Deno.openKv("locks"); | |
| const lock = await kv.get(key); | |
| if (lock.value) return false; | |
| return ( | |
| await kv.atomic() | |
| .check(lock) | |
| .set(key, "π", { expireIn: 1000 * 60 }) | |
| .commit() | |
| ).ok; | |
| } | |
| async function releaseLock(key: Deno.KvKey) { | |
| const kv = await Deno.openKv("locks"); | |
| await kv.delete(key); | |
| } | |
| async function backoff<T>(kv: Deno.Kv, key: Deno.KvKey) { | |
| for (let i = 0; i < 5; i++) { | |
| const item = await kv.get<T>(key); | |
| if (item.value) { | |
| log(`πβ got it after ${i} tries`); | |
| return item.value; | |
| } | |
| await sleep(100 + i * 100); | |
| } | |
| throw new Error("Could not backoff"); | |
| } | |
| function sleep(ms: number) { | |
| return new Promise((resolve) => { | |
| setTimeout(resolve, ms); | |
| }); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment