TODO: Write full article. Outline below — all sections are ready to expand.
Fly.io scales horizontally. Two machines in different regions means two independent
in-process IMemoryCache instances. When Machine A invalidates a cache entry, Machine B
has no idea it happened.
The naive solution — distributed locks — adds latency to every write path and introduces a new failure mode (lock server unavailability).
_listing_cache_key_registry)
alongside the in-process HashSet<string>InvalidateAllAsync(): read the registry, union with local set, remove everythingWalk through ListingCacheInvalidator.cs — TrackKey, InvalidateAllAsync, thread safety
with lock (_lock), and why ConfigureAwait(false) matters here.
Fire-and-forget means: if Redis is temporarily unreachable, keys created on Machine A during the outage won’t propagate to Machine B’s invalidation run. In practice this means a stale window of at most one TTL cycle. For a rental listings API (listings update infrequently), this is acceptable. For financial data it would not be.
If consistency were stricter — use Redis Pub/Sub to push invalidation events rather than polling the registry. This would close the stale window entirely.