You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
| [Cache variant complexity](docs/cache-variant-complexity.md) | Root/subkey storage model and operation complexity |
139
140
140
141
## Usage and configuration
141
142
@@ -145,10 +146,86 @@ wait0 checks RAM, then disk, and waits for the origin only on a cache miss. A ca
145
146
146
147
wait0 caches only `GET` responses with a `2xx` status, an allowed `Content-Type`, and no `Cache-Control: no-cache` or `no-store` directive. `cachableContentType` defaults to `text/html` and `application/xhtml+xml`, including values with parameters such as `text/html; charset=utf-8`. This keeps wait0 focused on controllable dynamic SWR; static assets should normally be cached by a CDN, Nginx, and browser caching.
147
148
148
-
An origin response that fails these checks is served as `X-Wait0: bypass` without being stored, with `X-Wait0-Reason` explaining why. If background revalidation receives a disallowed content type, either cache-control directive, or a non-`2xx` status, the existing entry is deleted; a network error leaves it available. A stale response is reported as `X-Wait0: hit`.
149
-
150
149
`logging.debug_headers` controls wait0 diagnostic response headers and the markers sent to the origin during revalidation. Omit it to enable every supported header, use a subset to select individual headers, or set `debug_headers: []` to disable all diagnostics. Functional headers such as `X-Wait0-CSRF` and origin-provided `X-Wait0-Tag` are not controlled by this option.
151
150
151
+
### Cache bypass
152
+
153
+
Request-side bypass rules are useful when a matching response must never be shared. They skip cache lookup, Cache-Variant evaluation, and storage:
154
+
155
+
```yaml
156
+
rules:
157
+
- match: PathPrefix(/admin)
158
+
bypass: true
159
+
160
+
- match: PathPrefix(/)
161
+
bypassWhenCookies: ['sessionid']
162
+
bypassWhenRequestHeaders: ['Authorization']
163
+
```
164
+
165
+
`bypass: true` applies to every request matching the rule. `bypassWhenCookies` applies when any named cookie is present. `bypassWhenRequestHeaders` applies when any named request header is present; header names are matched case-insensitively, and an explicitly present empty header still triggers the bypass. Bypassed and non-`GET` requests are sent upstream as bodyless `GET` requests.
166
+
167
+
When diagnostic headers are enabled, request-side decisions are reported as follows:
168
+
169
+
| Condition | `X-Wait0` | `X-Wait0-Reason` |
170
+
|-----------|-----------|------------------|
171
+
| `bypass: true` | `bypass` | `bypass-rule` |
172
+
| Cookie listed by `bypassWhenCookies` is present | `ignore-by-cookie` | `bypass-cookie` |
173
+
| Header listed by `bypassWhenRequestHeaders` is present | `ignore-by-request-header` | `bypass-request-header` |
174
+
| Request method is not `GET` | `bypass` | `non-get-method` |
175
+
176
+
wait0 can also fetch an origin response but decline to store it:
A non-cacheable miss response is returned to the client without being stored. If background revalidation receives a disallowed content type, either cache-control directive, or a non-`2xx` status, the existing entry is deleted; a network error leaves it available. A stale cached response is still reported as `X-Wait0: hit`.
187
+
188
+
### Cache variants
189
+
190
+
Cache variants are useful when an SSR origin renders the same URL differently by country, region, device, cookie, or another request header. The origin declares one or more `Cache-Variant` response headers containing [Expr](https://github.com/expr-lang/expr) expressions:
`"let c = header('CF-IPCountry', 'XX'); c == 'CA' && header('CF-Region-Code') == 'ON' ? 'CA-ON' : c"`
201
+
)
202
+
```
203
+
204
+
Each expression must return a string. Header names and fallbacks must be string literals. `header('Name')` requires the request header to exist; `header('Name', 'fallback')` supplies a value when it does not. The optional outer double quotes shown above are accepted. Multiple declarations are evaluated in response-header order and form a Cartesian variant family: the examples can produce keys such as `mobile|CA-ON` and `desktop|US`. Combinations are created lazily as requests discover them.
205
+
206
+
`X-Wait0-Cache-Variant-Key`reports the ordered values joined by `|`. Origin `Cache-Variant` headers remain visible in the client response for diagnosis. Invalid declarations use the expression-error behavior listed under [Cache bypass](#cache-bypass).
207
+
208
+
Discovered variants are monitored and warmed at their original URL using the request-header values that selected them. For example, discovering `mobile|CA` on `/a` adds a warmup target for `/a`; internal subcache keys are never requested from the origin.
209
+
210
+
You can seed additional request-header combinations on every warmup loop:
211
+
212
+
```yaml
213
+
rules:
214
+
- match: PathPrefix(/)
215
+
warmUp:
216
+
pauseBetweenRuns: '10s'
217
+
maxRequestsAtATime: 20
218
+
warmupRequestHeaderPresets:
219
+
CF-IPCountry: ['CA', 'US', 'UA']
220
+
User-Agent: ['iPad', 'Mozilla']
221
+
```
222
+
223
+
Preset values form a Cartesian product, so this example can make six requests per URL in addition to any distinct discovered variants. Known variant keys are deduplicated. This option can produce substantial origin traffic and cache growth; `warmUp.maxRequestsAtATime` still limits concurrency.
224
+
225
+
All request headers are allowed, including `Cookie` and authorization headers. wait0 persists the values of headers referenced by `header(...)` so a discovered variant can be refreshed later. Choosing sensitive headers is therefore the operator's responsibility: restrict cache/disk access and avoid expressions that retain secrets unless that storage is acceptable.
226
+
227
+
See [Cache variant complexity](docs/cache-variant-complexity.md) for the root-manifest, subkey, family, and warmup complexity guarantees.
228
+
152
229
### Query parameter caching
153
230
154
231
Cache keys use only the URL path by default, so `/blog`, `/blog?page=1`, and `/blog?utm_source=email` share the same cached response. The first cold request reaches the origin with its complete query and fills the shared entry; later background refreshes omit query parameters that are not in `varyByQueryParams`.
@@ -236,6 +313,8 @@ rules:
236
313
priority: 2
237
314
# Bypasses cache when any named cookie is present.
238
315
bypassWhenCookies: ['sessionid']
316
+
# Bypasses cache when any named request header is present.
317
+
bypassWhenRequestHeaders: ['Authorization']
239
318
# Exact media types eligible for wait0 caching. Parameters such as charset
240
319
# are ignored. Defaults to the two values shown here.
# Maximum concurrent requests for this warmup rule.
251
330
maxRequestsAtATime: 20
331
+
# Optional Cartesian header presets used on every warmup loop.
332
+
warmupRequestHeaderPresets:
333
+
CF-IPCountry: ['CA', 'US', 'UA']
334
+
User-Agent: ['iPad', 'Mozilla']
252
335
253
336
logging:
254
337
# Diagnostic response headers and origin revalidation markers. Omit this
@@ -261,6 +344,7 @@ logging:
261
344
- X-Wait0-Discovered-By
262
345
- X-Wait0-Revalidate-At
263
346
- X-Wait0-Revalidate-Entropy
347
+
- X-Wait0-Cache-Variant-Key
264
348
# To disable every diagnostic header, replace the list above with:
265
349
# debug_headers: []
266
350
# Logs a stats snapshot at this interval; omit to disable.
@@ -291,6 +375,7 @@ If you do not restart between deploys, proactively refresh cache using invalidat
291
375
292
376
- Request pipeline: RAM cache -> disk cache -> origin.
293
377
- Cache key is path-only by default.
378
+
- A variant URL stores a constant-size root manifest; evaluated values select response subkeys without scanning sibling variants.
294
379
- Rule field `varyByQueryParams[]` opts specific query parameters into cache identity for matching paths.
295
380
- Query parameters not listed in `varyByQueryParams[]` and all fragments are ignored for cache identity.
296
381
- Only `GET` requests are cache candidates.
@@ -299,3 +384,4 @@ If you do not restart between deploys, proactively refresh cache using invalidat
299
384
- Rule `expiration` marks entries stale but does not evict them; stale responses are served immediately and revalidation is scheduled on a best-effort basis.
300
385
- On a cache-path miss or revalidation, an origin non-`2xx` is not cached and any existing key is evicted.
301
386
- Invalidation is asynchronous: accept request -> resolve keys by `paths` and `tags` -> delete keys -> recrawl in background. Path invalidation clears all cached query-aware variants for that path.
387
+
- Warmup monitors discovered cache variants and may expand `warmupRequestHeaderPresets` into additional Cartesian request-header combinations.
0 commit comments