Skip to content

feat(core): add soft purge support#738

Open
kasparsd wants to merge 5 commits intodarkweak:masterfrom
kasparsd:feature/soft-purge
Open

feat(core): add soft purge support#738
kasparsd wants to merge 5 commits intodarkweak:masterfrom
kasparsd:feature/soft-purge

Conversation

@kasparsd
Copy link
Copy Markdown

@kasparsd kasparsd commented Mar 29, 2026

Summary

A soft purge marks cached entries stale instead of deleting them immediately, so the stale response can still be served while a background refresh or revalidation updates the object. This is similar to Nginx fastcgi_cache_use_stale: updating.

Created this while researching alternatives to Fastly's surrogate keys with soft purge, as it is super useful for large publishers that frequently publish content and want to ensure that end-user never experience slow response time (arriving on cold, invalidated responses).

Changes

  • add soft purge detection through the Souin-Purge-Mode: soft header
  • keep cached objects and surrogate mappings on soft purge, while marking them stale
  • serve soft-purged responses with Cache-Status ... fwd=stale
  • trigger background refresh for soft-purged responses
  • prefer conditional revalidation when validators are available
  • deduplicate concurrent background refreshes
  • reject soft purge on /flush
  • keep bypass_request behavior unchanged for normal request handling
  • avoid resetting shared storage on flush when clearing surrogate indexes

Caddy / middleware fixes included

This also fixes the background revalidation path used by Caddy so the refresh does not reuse a canceled request context.

It also restores generic stale-while-revalidate behavior in strict and bypass_request modes.

Tests

Added coverage for:

  • soft purge request detection and API behavior
  • soft purge stale serve + background refresh
  • conditional revalidation with 304 Not Modified
  • bypass_request behavior with soft purge
  • generic stale-while-revalidate in strict mode
  • generic stale-while-revalidate in bypass_request mode
  • cached responses not replaying the stored Server header
  • surrogate flush clearing indexes without closing shared storage

Related

Disclaimer: GPT-5.4 was used to create the majority of this change.

…request modes

Serve expired entries within their stale-while-revalidate window in the generic
middleware path not only when the request sends max-stale.

This updates stale validation to honor response-side stale-while-revalidate in
strict mode, and moves generic background revalidation onto a detached request
context so async refresh can complete after the client request ends.

Also adds regression coverage for stale-while-revalidate behavior in strict and
bypass_request modes, plus an RFC-level test for SWR stale age validation.
@netlify
Copy link
Copy Markdown

netlify bot commented Mar 29, 2026

Deploy Preview for teal-sprinkles-4c7f14 canceled.

Name Link
🔨 Latest commit f3acd98
🔍 Latest deploy log https://app.netlify.com/projects/teal-sprinkles-4c7f14/deploys/69c98f098c8bec000802ff3c

@darkweak darkweak added the Next release It will be in the next release label Apr 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Next release It will be in the next release

Projects

None yet

2 participants