Add a [cdn] section and purge the edge after publishing
The site is about to sit behind Cloudflare, where the public pages will be allowed to live at the edge for a day (`s-maxage`, next commit). That is only correct if the edge is emptied the moment a new issue lands, so the origin now does the emptying itself rather than leaving it to an operator to remember. `[cdn]` is inert by default: with no `provider` nothing is called and no token is needed, so an origin with no CDN behaves exactly as before. Setting `provider = "cloudflare"` without both a zone id and `DAILY_EPUB_CDN__API_TOKEN` is a config error — a half-configured purge would publish into a stale edge and say nothing. The purge is `purge_everything` on purpose. A new issue changes more than its own page: `/`, `/issues`, `/feed.xml`, `/issues.json`, and the previous issue's page too, whose "latest" nav marker moves. A per-URL list of that set is exactly the kind of thing that silently rots, and everything expensive at the edge is content-hashed, so refilling it costs one origin fetch. A purge failure is logged at warn and never fails the run: the paper is already published and recorded by then, and a few stale hours are not worth failing over. `daily-epub cdn purge` runs the same code by hand; it takes no run lock because it touches neither the database nor the publish directories. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Va5eMEmWEnjMXBsBob5FDW
This commit is contained in:
@@ -786,6 +786,11 @@ async fn run_stages(
|
||||
record_issue(db, &issue, &published)
|
||||
.await
|
||||
.context("recording the issue")?;
|
||||
// The edge holds the public pages for `s-maxage=86400`, so it has to be
|
||||
// told the day changed. Best effort: the paper is already published and
|
||||
// recorded, and a stale edge for a few hours is not worth failing a run
|
||||
// that otherwise succeeded (§3.12).
|
||||
purge_cdn(config).await;
|
||||
Some(published)
|
||||
};
|
||||
report.timings.record("publish", elapsed_ms(stage));
|
||||
@@ -798,6 +803,23 @@ async fn run_stages(
|
||||
})
|
||||
}
|
||||
|
||||
/// Purge the CDN after a successful publish, never failing the run.
|
||||
async fn purge_cdn(config: &Config) {
|
||||
if !config.cdn.purge_after_publish {
|
||||
tracing::debug!("cdn purge skipped: cdn.purge_after_publish is false");
|
||||
return;
|
||||
}
|
||||
match crate::cdn::purge_all(config).await {
|
||||
Ok(crate::cdn::PurgeOutcome::Disabled) => {
|
||||
tracing::debug!("cdn purge skipped: no cdn.provider configured");
|
||||
}
|
||||
Ok(outcome) => tracing::info!("{outcome}"),
|
||||
Err(error) => {
|
||||
tracing::warn!(%error, "the CDN cache purge failed; the edge may serve the previous issue until its s-maxage expires")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Near misses listed in the "Behind the paper" chapter (§15.1).
|
||||
const NEAR_MISSES_IN_PAPER: usize = 10;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user