Skip to content

Measure whether warmup requests reach the origin behind the Cloudways CDN #135

Description

@parisek

Corrected 2026-08-24. The original version of this issue claimed the Cloudflare purge is deferred to WP-Cron and therefore has not happened when warming starts. That is wrong for the full-purge path. See the correction comment below; the body has been rewritten to match what the source actually does.

On a site behind the Cloudways CDN (Cloudflare Enterprise, full-page caching), a warmup request travels through the edge before it can reach the origin. If the edge still holds the page, it answers from cache, the origin never renders, and Breeze never writes its file cache. This issue is about establishing how much of a real risk that is.

Everything below is read out of the plugin source. Nothing here has been measured.

What the source actually does

On a full purge the Cloudflare purge is synchronous and blocking:

// class-breeze-cloudflare-helper.php — request_cache_reset()
if ( 'cron' === $purge_type ) {
    // deferred: spawn_cron(), or immediate when already DOING_CRON
} else {
    return $this->execute_purge( $purge_url_list, $endpoint_path );
}

reset_all_cache() calls request_cache_reset() without a purge type, so it takes the else branch. execute_purge() uses curl_exec with CURLOPT_RETURNTRANSFER and CURLOPT_TIMEOUT = 30 — it waits for the Cloudways microservice to answer.

Hook order on breeze_clear_all_cache:

Priority Action
10 Breeze_Admin::breeze_clear_all_cache — clears local cache, purges Cloudflare inline and blocking
999 Breeze_Cache_Preloader::schedule_preload — warms the first URL, queues the rest

So the purge API call has returned before warming starts. The ordering is correct and the mechanism is sound.

The deferred spawn_cron() path exists, but only for $purge_type === 'cron' — it is not what a full purge uses.

What is still worth checking

The purge API returning is not the same as the purge having taken effect on every edge node. Cloudflare purge-by-URL is normally fast, but it is not atomic across the network, and the preload fires milliseconds after the API call returns.

The queue then drains at roughly a second per URL over minutes, so any propagation lag would affect only the first few URLs — not the whole run. That is a much smaller problem than originally described, and it may be no problem at all.

Worth noting separately: Breeze's purge and its preload deliberately talk to different layers. Purge reaches Varnish on 127.0.0.1 (inc/cache/purge-varnish.php) and Cloudflare through the microservice; preload goes out through the public hostname. That asymmetry is by design, but it is why a warmup can only ever fill the layers that miss.

How to measure

On one Cloudways project with the CDN enabled:

  1. Trigger a full purge (admin bar, or wp breeze purge --all).
  2. Watch the origin access log.
  3. Count how many of the warmup requests arrive, and whether the misses cluster at the start of the run.

Breeze tags them X-Breeze-Preload: 1, though nothing in the plugin reads that header back — it is only a marker.

Outcomes:

  • All requests arrive — close this issue with the measurement recorded. No work needed.
  • The first few are missing — propagation lag, as suspected. A short delay before the first warm, or warming the first URL last, would cover it cheaply.
  • Most or all are missing — something else is going on and the layering needs a proper look before Periodic warmup: drain the tail beyond the URL cap on a schedule #136 proceeds.

Relationship to other work

The ordering feature merged in #134 is unaffected in its own logic. Its score, cap and queue order are correct, and it works without reservation on sites with no edge HTML cache.

#136 (periodic warmup) is blocked on this measurement — not because the mechanism is broken, but because building a scheduled warmer on an unverified assumption about where requests land would be building on sand.

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions