De cache werkte, maar veroorzaakte toch dubbele API-aanroepen
De cache was niet kapot.
Toch resulteerden drie gelijktijdige verzoeken voor dezelfde gebruikersnaam in drie aparte aanroepen naar GitHub.
Dit gebeurde in CommitPulse, een Next.js API die GitHub-gegevens omzet in SVG-badges. Wanneer een README viraal gaat, bekijken duizenden mensen de badge tegelijkertijd. Dit zorgt voor enorme hoeveelheden verkeer.
De cache werkte voor opeenvolgende verzoeken. Het faalde bij gelijktijdige verzoeken.
Dit is het probleem:
- Verzoek A controleert de cache. Het is een miss. Verzoek A begint met ophalen van gegevens bij GitHub.
- Verzoek B arriveert 5 ms later. Het controleert de cache. Het is nog steeds een miss omdat verzoek A nog niet klaar is. Verzoek B start een tweede ophaalactie.
- Verzoek C arriveert 10 ms later. Dit ziet ook een cache miss en start een derde ophaalactie.
Dit is het thundering herd-probleem. Een cache miss onder hoge belasting veroorzaakt een vloedgolf aan identieke aanroepen naar je upstream-provider. Als je een API gebruikt met een limiet op het aantal aanroepen, zoals GitHub, kan dit je limieten onmiddellijk uitputten.
De oplossing is request coalescing.
Je moet lopende verzoeken apart bijhouden van voltooide cache-vermeldingen. Ik heb een in-flight Map geïmplementeerd om dit te beheren:
- Wanneer een verzoek start, sla je de Promise op in een Map.
- Als er een tweede verzoek binnenkomt voor dezelfde sleutel, start dan geen nieuwe ophaalactie.
- Geef in plaats daarvan de bestaande Promise uit de Map terug.
- Zodra het verzoek klaar is, verwijder je het uit de Map en sla je het resultaat op in de cache.
Dit zorgt ervoor dat, ongeacht hoeveel mensen tegelijkertijd dezelfde gegevens opvragen, er slechts één aanroep naar de API gaat.
Terwijl ik dit oploste, heb ik ook drie andere edge-case bugs in hetzelfde bestand opgelost:
- Ontbrekende token-fouten: Het systeem stuurde "undefined" als inloggegevens. Ik heb dit aangepast zodat tokens worden gevalideerd voordat er verzoeken worden gedaan.
- Geheugenlekken: De retry-logica liet verouderde event listeners achter op AbortSignals. Ik heb opruimlogica toegevoegd om lekken te voorkomen.
- URL-injectie: Gebruikersnamen met speciale tekens beschadigden de API-paden. Ik heb encoding toegevoegd om de URL-structuur te beschermen.
Een cache is niet voldoende. Je moet ook verzoeken die momenteel in uitvoering zijn, dedupliceren.
Bron: https://dev.to/eshaanagrawal/the-cache-was-working-and-still-causing-duplicate-api-calls-3n51
