Skip to content

HTML Cache Invalidation

HTML Cache stores cached HTML files, an index of which models were seen while rendering each URL, and optionally a stale URL queue for scheduled refreshes. Clear or refresh both when a package changes content that may already be cached.

The default invalidation mode is instant, which keeps the existing behaviour: model and routing changes delete affected cached files immediately. Enable scheduled invalidation with:

CAPELL_HTML_CACHE_INVALIDATION_MODE=scheduled
CAPELL_HTML_CACHE_INVALIDATION_SCHEDULE=everyFiveMinutes
CAPELL_HTML_CACHE_INVALIDATION_BATCH_SIZE=100
CAPELL_HTML_CACHE_PROCESSING_TIMEOUT_MINUTES=15
CAPELL_HTML_CACHE_RETRY_BACKOFF_MINUTES=5
CAPELL_HTML_CACHE_MAX_ATTEMPTS=5

In scheduled mode, model changes insert rows into stale_cached_urls instead of deleting cached files immediately. The scheduler runs capell:html-cache:process-stale on the configured cadence, renders fresh HTML through the Laravel kernel, and atomically replaces the existing cache file only after the refreshed response is safe and cacheable.

Site-domain scheme, host, path, site, and language mutations still clear the HTML cache immediately, even in scheduled mode. Those changes can make the old file path or public URL unsafe to serve while waiting for the next cycle.

If a stale URL no longer resolves to an enabled site domain, the processor treats that as confirmation that the old public cache entry is obsolete, deletes the old cache files, and removes matching cached_model_urls rows.

Failed refreshes retry after the configured backoff until max_attempts is reached. Rows that keep failing are marked exhausted for diagnostics and manual follow-up instead of being retried forever.

ActionUse it when
ClearCachedUrlActionYou know the public URL that should be removed from the cache.
ClearCachedPageUrlsActionYou have a collection of URLs and want a simple count of cleared entries.
ClearCachedUrlsForModelActionYou changed one model and want to clear every cached URL that referenced it.
MarkCachedUrlStaleActionYou know a URL should be refreshed on the next scheduled cycle.
MarkCachedUrlsForModelStaleActionYou changed one model and want scheduled mode to refresh indexed URLs.
MarkAllCachedUrlsStaleActionBroad routing/domain changes should queue all indexed URLs as stale.
ProcessStaleHtmlCacheActionProcess pending stale URLs and atomically refresh their cached HTML.
RecordCachedModelUrlsActionA render pass knows which models contributed to a cached URL.
GenerateStaticSiteActionA full static generation run is needed for one Site.
GenerateStaticSitesActionStatic generation should run for all selected sites.

The admin cache map reads cached_model_urls; it does not scan public HTML on every request. If a package renders model-backed content but never records dependencies, cache invalidation can only work by URL.

use Capell\HtmlCache\Actions\ClearCachedUrlAction;
ClearCachedUrlAction::run('https://example.test/about', refresh: true);

refresh: true dispatches Capell\Core\Actions\VisitUrlAction after the file and index rows are removed. Use it only when the URL should be warmed immediately.

use Capell\HtmlCache\Actions\ClearCachedUrlsForModelAction;
$cleared = ClearCachedUrlsForModelAction::run($article, refresh: false);

This looks up rows where cacheable_type matches $article->getMorphClass() and cacheable_id matches the model key. If the model was never recorded with RecordCachedModelUrlsAction, the action returns 0.

use Capell\HtmlCache\Actions\RecordCachedModelUrlsAction;
RecordCachedModelUrlsAction::run($url, [
$article->getMorphClass() => [$article->getKey()],
$author->getMorphClass() => [$author->getKey()],
]);

RecordCachedModelUrlsAction resolves the site domain and path from the URL, upserts the current dependencies, and removes stale dependencies for the same URL hash.

KeyPurpose
capell-html-cache.enabledTurns HTML cache behaviour on or off.
capell-html-cache.write_enabledAllows cache writes. Disable this when investigating output safety.
capell-html-cache.minify_htmlControls minification before writing cached HTML.
capell-html-cache.cache_ttlDefault cache TTL.
capell-html-cache.cache_skip_authenticatedKeeps authenticated responses out of the public cache.
capell-html-cache.invalidation.modeinstant or scheduled. Default instant.
capell-html-cache.invalidation.scheduleScheduler frequency for stale processing. Default everyFiveMinutes.
capell-html-cache.invalidation.batch_sizeDefault stale URL batch size.
capell-html-cache.invalidation.processing_timeout_minutesMinutes before a processing stale row may be claimed again.
capell-html-cache.invalidation.retry_backoff_minutesMinutes before a failed stale row may be retried.
capell-html-cache.invalidation.max_attemptsMaximum refresh attempts before a stale row becomes exhausted.
capell-html-cache.model_event_registration_modeControls model event registration timing; default is deferred.
capell-html-cache.static_generation.internal_requestsLets static generation render through the current Laravel kernel.
capell-html-cache.public_html_authoring_markersStrings used by diagnostics to detect authoring leakage in public HTML.
Terminal window
vendor/bin/pest packages/html-cache/tests --configuration=phpunit.xml

The package command is:

capell:html-cache:process-stale {--limit=}
capell:static-site {--site=} {--internal} {--refresh}

capell:html-cache:process-stale is scheduled automatically when capell-html-cache.invalidation.mode is scheduled. --limit overrides the configured batch size for one run.

--internal renders through the current Laravel kernel. --refresh deletes affected cached files before rendering.

Implement Capell\HtmlCache\Contracts\PageCacheNotifiable when a class needs to react after a page cache entry is recorded:

use Capell\HtmlCache\Contracts\PageCacheNotifiable;
use Illuminate\Database\Eloquent\Model;
final class SearchIndexCacheNotifier implements PageCacheNotifiable
{
public function notifyPageCached(Model $model): void
{
// Keep side effects small; this runs from cache recording paths.
}
}

Keep notifications cheap. Cache writes happen on public page renders, so slow work belongs on a queue.

HTML Cache must remain safe for anonymous visitors, signed-in users, admins, crawlers, and static exports. Do not put authoring attributes, model IDs, signed editor URLs, field paths, package names, or permission hints into cached HTML. If a package needs admin editing, use Frontend Authoring’s post-load beacon.