Skip to content

purge($uri) does not evict donut template entries #185

Description

@koriym

Found during the semantic-log review of #178: the log showed save_donut{tags: [], ttl: null, saved: true} for donut resources that declare no Surrogate-Key header — an entry no invalidation can reach.

Root cause

DonutRepository::putDonut() reads getHeaderKeys($ro) at line 78 BEFORE $keys->setSurrogateHeader($ro) at line 81 (same in putStatic(): line 57 before line 60). The donut template entry is therefore saved with only the resource's self-declared Surrogate-Key header tags; the auto-assembled SurrogateKeys (own URI tag + embedded child tags) never reach the template entry.

For a donut resource with no self-declared Surrogate-Key this means tags: []. Symfony's TagAwareAdapter freshness check iterates the item's tags, so an empty-tag item is never staled by any invalidateTags() call. On the interceptor path the TTL is also null (putStatic($ro, null, null) / putDonut($ro, null)), so the template entry is effectively immortal: the only eviction path is a same-key overwrite.

Reproduction

GET a #[DonutCache] page with no declared Surrogate-Key → purge() its own URI → GET again: manual_purge_result reports purged, but the next GET closes cache_hit{donut} and emits refresh_donut — the shell is reused. The purge succeeds against content/ETag entries but is a no-op against the donut template.

Note the #[DonutCache] docblock promises tag-based invalidation ("Unlike #[Cacheable] which uses TTL-based expiration, this enables tag-based invalidation"), which currently does not work for the template entry.

Fix direction

Move the getHeaderKeys($ro) call after setSurrogateHeader($ro) so the template entry carries its own URI tag (and child tags). This widens the template's tag set and therefore changes cascade-invalidation behavior, so it needs its own PR with a design review — deliberately kept out of #178 (logging-only).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions