From 6ab849be5eff86eb2a474dd5f81a15cfb8c480d0 Mon Sep 17 00:00:00 2001 From: Shekhar Vaidya Date: Fri, 31 Jul 2026 11:35:44 +0530 Subject: [PATCH] fix(backend): back off Sentinel lockdown retries, validate product_id in /proxy Log analysis over 17 days showed 181 Sentinel-block retry attempts on /proxy, all 181 failed (0% success). Retrying every 90 minutes yields zero value right now and just adds more blocked-request noise against our own IP for nothing in return. Bumped lockdownTTL to 5h so it backs off harder while still recovering same-day if Microsoft's block ever eases. Also found /proxy never validated product_id against the known catalog, so a request for a nonexistent ID (e.g. product_id=2861, never a real product) still burned a full outbound Microsoft session attempt and a Sentinel-block hit for something that could never succeed anyway. Now rejected with 404 before any Microsoft call, reusing the existing validContributeProducts allow-list. Verified locally: unknown product_id -> 404 (no MS fetch attempted in logs), missing params -> 400 unchanged, known product_id -> proceeds to a real MS session attempt as before. Co-Authored-By: Claude Sonnet 4.6 --- backend/main.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/backend/main.go b/backend/main.go index c753cf7..9d274d7 100644 --- a/backend/main.go +++ b/backend/main.go @@ -132,7 +132,7 @@ func truncateBody(s string) string { return s } -// --- Negative cache (60s normal / 90min Sentinel lockdown) --- +// --- Negative cache (60s normal / 5h Sentinel lockdown) --- type negCacheEntry struct { Message string @@ -145,7 +145,10 @@ var ( negCache = make(map[string]negCacheEntry) negCacheMu sync.RWMutex negCacheTTL = 60 * time.Second - lockdownTTL = 90 * time.Minute + // Bumped from 90min on 2026-07-31: 181 retry attempts over 17 days, 0 successes. + // Retries yield zero value right now, so back off harder instead of hammering + // Microsoft (and our own IP's reputation) every 90 minutes for nothing. + lockdownTTL = 5 * time.Hour ) // --- Singleflight (one in-flight Microsoft fetch per unique key) --- @@ -1184,6 +1187,10 @@ func handleProxy(w http.ResponseWriter, r *http.Request) { respondJSONError(w, http.StatusBadRequest, "sku_id contains invalid characters") return } + if !validContributeProducts[productID] { + respondJSONError(w, http.StatusNotFound, "unknown product_id") + return + } atomic.AddInt64(&mLinkRequests, 1) cacheKey := productID + ":" + skuID @@ -1301,7 +1308,7 @@ func handleProxy(w http.ResponseWriter, r *http.Request) { atomic.AddInt64(&mLinkStale, 1) if isSentinel { - // Sentinel lockdown: set 90-min neg cache, add lockdown header, skip + // Sentinel lockdown: set lockdownTTL neg cache, add lockdown header, skip // background refresh — retrying extends the Sentinel block timer. negCacheMu.Lock() negCache[negKey] = negCacheEntry{ @@ -1311,7 +1318,7 @@ func handleProxy(w http.ResponseWriter, r *http.Request) { IsSentinel: true, } negCacheMu.Unlock() - log.Printf("/proxy: product_id=%s sku_id=%s -> Sentinel lockdown (90min), serving stale\n", productID, skuID) + log.Printf("/proxy: product_id=%s sku_id=%s -> Sentinel lockdown (%s), serving stale\n", productID, skuID, lockdownTTL) w.Header().Set("X-MSDL-Lockdown", "1") w.Header().Set("X-MSDL-Link-Status", "stale") if exp := extractRawExpiry(cached.RawJSON); exp != "" { @@ -1365,7 +1372,7 @@ func handleProxy(w http.ResponseWriter, r *http.Request) { } negCacheMu.Unlock() if isSentinel { - log.Printf("/proxy: product_id=%s sku_id=%s -> Sentinel lockdown (90min), no stale\n", productID, skuID) + log.Printf("/proxy: product_id=%s sku_id=%s -> Sentinel lockdown (%s), no stale\n", productID, skuID, lockdownTTL) w.Header().Set("X-MSDL-Lockdown", "1") w.WriteHeader(code) json.NewEncoder(w).Encode(map[string]interface{}{ -- 2.45.3