Fix: Extended ResourcePool never updates stale cached entries#342
Conversation
The `save()` method in `Extended` has two issues that prevent cached entries from ever being updated once initially stored: 1. `parent::save()` returns `false` when the resource already exists in the in-memory pool (e.g. loaded by `warmUp()`). This causes `Extended::save()` to bail out before reaching the cache write, so the PSR-6 cache is never updated with fresh data. 2. The `$cacheItem->isHit()` guard skips writing when the key already exists in the cache, even if the data has changed. Combined, these two checks mean that once an Entry or Asset is cached, the SDK can never update it — even when a fresh version is fetched from the API. The only way to get fresh data is to flush the entire cache. This is particularly problematic in applications that use webhook-based cache invalidation: after invalidating the application-level cache, the SDK's ResourcePool still serves stale data from its PSR-6 cache, and fresh API responses cannot overwrite it. The fix: - Always proceed to the cache write regardless of `parent::save()`'s return value (the in-memory pool is still updated by the parent) - Remove the `isHit()` guard so stale cache entries are overwritten Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Code Review Agent Run #d14bb7Actionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
Changelist by BitoThis pull request implements the following key changes.
|
Impact Analysis by BitoInteraction DiagramsequenceDiagram
participant Client
participant ResourceBuilder
participant Extended as Extended ResourcePool<br/>🔄 Updated | ●●○ Medium
participant Standard as Standard ResourcePool
participant Cache as PSR Cache Pool
Client->>ResourceBuilder: build(resource data)
ResourceBuilder->>Extended: save(resource)
Extended->>Standard: parent::save(resource)
Standard-->>Extended: return result
alt [autoWarmup enabled && type in warmupTypes]
Extended->>Cache: getItem(cacheKey)
Cache-->>Extended: return CacheItem
Extended->>Cache: set(encoded resource)
Extended->>Cache: save(CacheItem)
end
Extended-->>ResourceBuilder: return true
ResourceBuilder-->>Client: return built resource
Note over Extended: Always performs cache update<br/>removed hit check for freshness
The Extended ResourcePool's save method now always updates the cache for auto-warmup resource types, even if the cache item was already present, ensuring data freshness but potentially increasing cache write operations. This change affects resource fetching in the Contentful PHP SDK by modifying cache behavior during resource building. Code Paths AnalyzedImpact: Flow: Direct Changes (Diff Files): Repository Impact: Cross-Repository Dependencies: Database/Caching Impact: API Contract Violations: Infrastructure Dependencies: Testing RecommendationsFrontend Impact: Service Integration: Data Serialization: Privacy Compliance: Backward Compatibility: OAuth Functionality: Reliability Testing: Additional Insights: Analysis based on known dependency patterns and edges. Actual impact may vary. |
Summary
The
save()method inExtendedResourcePool has two issues that prevent cached entries from ever being updated once initially stored in the PSR-6 cache.Bug 1:
parent::save()gates the cache writeStandard::save()returnsfalsewhen the resource already exists in the in-memory pool — which is the case wheneverwarmUp()has loaded it from cache earlier in the same request.Extended::save()treats thisfalseas "nothing to do" and returns before reaching the PSR-6 cache write:Bug 2:
isHit()prevents overwritingEven if bug 1 didn't exist, the
isHit()guard explicitly prevents overwriting existing cache entries:Combined effect
Once an Entry or Asset is cached in the PSR-6 pool, the SDK can never update it even when a fresh version is fetched directly from the Contentful API. The only way to get fresh data is to flush the entire cache store.
Reproduction
cacheContent: trueandautoWarmup: truegetEntries()it gets cached in the PSR-6 poolgetEntries()the API returns fresh datawarmUp()loads the stale version from the PSR-6 cache, becausesave()never wrote the fresh versionFix
parent::save()'s return value. The in-memory pool is still updated by the parent call, but we always proceed to the cache writeisHit()guard so stale cache entries are overwritten with fresh dataSummary by Bito
The PR fixes a bug in the Extended ResourcePool where cached entries were never updated once stored in the PSR-6 cache. The save() method had two issues: it gated cache writes based on parent::save() return value and prevented overwriting existing cache entries with an isHit() check. This combined effect meant stale data persisted indefinitely. The fix ignores the parent return value and removes the isHit() guard to ensure fresh API data always updates the cache.
Detailed Changes