Rules Hub
Coding Rules Library
Rule priority, scope & exceptions
Use this to align rules with the senior-level structure (P0/P1/P2, scope, exceptions/tradeoffs).
Keep concurrent-miss coalescing when you reimplement a cache wrapper
A plain get-miss-compute-set wrapper runs the expensive function once per concurrent caller, so at every TTL boundary on a hot key the load on the backing store is multiplied by request concurrency. Deduplicate in-flight misses on the same key with a promise map.
Bad example
| 1 | async wrap(key, fn, { ttl }) { |
| 2 | const hit = await this.get(key); |
| 3 | if (hit !== null) return hit; |
| 4 | const value = await fn(); // N concurrent misses -> N executions |
| 5 | await this.set(key, value, ttl); |
| 6 | return value; |
| 7 | } |
Explanation (EN)
Every request that misses runs its own expensive query, so an expiring hot key sends a burst of identical work to the backing store.
Objašnjenje (HR)
Svaki zahtjev koji promasi pokrece vlastiti skupi upit, pa istekli vruci kljuc salje val identicnog posla prema izvoru podataka.
Good example
| 1 | private inFlight = new Map<string, Promise<unknown>>(); |
| 2 |
|
| 3 | async wrap<T>(key: string, fn: () => Promise<T>, { ttl }): Promise<T> { |
| 4 | const hit = await this.get<T>(key); |
| 5 | if (hit !== null) return hit; |
| 6 |
|
| 7 | const existing = this.inFlight.get(key); |
| 8 | if (existing) return existing as Promise<T>; |
| 9 |
|
| 10 | const pending = fn() |
| 11 | .then(async (value) => { |
| 12 | await this.set(key, value, ttl); |
| 13 | return value; |
| 14 | }) |
| 15 | .finally(() => this.inFlight.delete(key)); |
| 16 |
|
| 17 | this.inFlight.set(key, pending); |
| 18 | return pending; |
| 19 | } |
Explanation (EN)
Concurrent misses share one execution and one result, so the backing store sees a single query per key per TTL window.
Objašnjenje (HR)
Istovremeni promasaji dijele jedno izvrsavanje i jedan rezultat, pa izvor podataka vidi jedan upit po kljucu unutar jednog TTL prozora.
Notes (EN)
Clear the map in a finally so a rejected computation cannot wedge the key. This is roughly five lines and it is the main thing a cache wrapper buys you beyond a raw get and set.
Bilješke (HR)
Ocisti mapu u finally bloku kako odbijeno izracunavanje ne bi zaglavilo kljuc. To je otprilike pet linija i glavno je sto ti omotac cachea donosi povrh golog get i set.