Problem/Motivation
GSMI's cached derivative images are keyed by the node's changed timestamp, so editing a node makes future page renders resolve a brand-new image URL, and GsmiImageManager::invalidateSocialImage() deletes the old cached file on hook_entity_update().
That's correct for anyone who re-fetches the page — they get the new URL. But external consumers that cache the image URL itself independently of the page (CDN edge caches, social-media crawlers like Facebook's/Twitter's og:image fetchers, browsers with a cached response) can still hold a reference to the old URL. Once the old file is deleted, a request to that URL simply 404s, with no way to recover the current image.
Proposed resolution
Add a fallback route that catches requests for a derivative that no longer exists on disk and redirects (302, Cache-Control: no-store) to the node's current derivative instead of returning a 404.
This required a bigger change than just adding a distinguishing path segment: GSMI's cache previously lived nested inside the image style's own derivative directory ({scheme}://styles/{style}/{scheme}/{nid}/{field}/{timestamp}/...). Core's image module registers an inbound path processor (PathProcessorImageStyles) that unconditionally intercepts any request under {scheme}://styles/... before routing runs, so a custom GSMI route nested in that same tree would never actually be reached — core's own image-style regeneration logic would claim the request first (and fail, since the GSMI-specific path segments aren't a valid source image path).
The fix moves GSMI's cache to its own sibling tree, {scheme}://gsmi/{style}/{nid}/{field}/{timestamp}/{filename}, completely outside the styles/ prefix core claims. A new route_callbacks class (GsmiStaleImageRoutes, mirroring core's own Drupal\image\Routing\ImageStyleRoutes) registers a route matching that path, backed by a new GsmiController::redirectStaleDerivative() method that reloads the node, resolves (regenerating if needed) its current derivative, and redirects to it.
Changes
GsmiGenerator:cache path moved out from under the image style's ownstyles/directory into{scheme}://gsmi/{style}/....- New
GsmiStaleImageRoutes+GsmiController::redirectStaleDerivative()for the fallback redirect. - Updated/added unit and kernel test coverage for the new path structure and the redirect controller.
README.md/AGENTS.mdupdated to document the new cache layout and stale-URL fallback behavior.
Remaining limitations
This only helps requests that reach the origin again (a CDN's own TTL expiring, a crawler re-fetching, a browser reload) — it can't retroactively fix bytes a client already cached locally without re-requesting.
Issue fork gsmi-3610139
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #4
mandclu commented