From 220988c02ed9c541d1a2b29f27c4b99b731d87d7 Mon Sep 17 00:00:00 2001 From: Semih Yesilyurt Date: Fri, 5 Jun 2026 16:09:45 +0300 Subject: [PATCH] fix(categories): don't cache an empty category tree for an hour MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit getCategoryTree cached the built tree for 3600s unconditionally, and the read guard `if (cached)` treats an empty array as a hit. So a single transient decode/proxy failure (emex via the flaky DataImpulse pool) seeded 0 categories and poisoned the catalog with an empty tree for a full hour, even after the source recovered. Cache an empty tree for only 60s — it self-heals on the next request post-recovery while still throttling re-decode during a genuine outage. Co-Authored-By: Claude Opus 4.8 --- apps/api/src/categories/categories.service.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/api/src/categories/categories.service.ts b/apps/api/src/categories/categories.service.ts index ed6e206..9c1bea6 100644 --- a/apps/api/src/categories/categories.service.ts +++ b/apps/api/src/categories/categories.service.ts @@ -420,7 +420,11 @@ export class CategoriesService { // Build tree const tree = this.buildTree(dbCategories); - await this.redis.setJson(cacheKey, tree, 3600); + // Cache a populated tree for an hour; an EMPTY tree (transient decode/proxy + // failure) only for 60s so a blip doesn't poison the catalog for an hour — + // it self-heals on the next request after the source recovers, while still + // throttling re-decode attempts during a real outage. + await this.redis.setJson(cacheKey, tree, tree.length > 0 ? 3600 : 60); return tree; }