Cache Invalidation

cloud-vinyl supports three invalidation mechanisms, all broadcast to every pod in the cluster.

PURGE (object-level)

A standard HTTP PURGE request removes a single cached object by URL. Varnish must have return(purge) in vcl_recv for the PURGE method (generated automatically).

Soft purge (default, spec.invalidation.purge.soft: true) marks objects as stale instead of removing them. Subsequent requests revalidate in the background (stale-while-revalidate). This prevents cache stampedes on busy endpoints.

Send a purge via the operator proxy:

PURGE http://<operator-svc>:8090/path/to/resource

BAN (expression-based)

Bans invalidate sets of objects matching a VCL expression. Two routes are available — they differ in where the expression is validated and in how the ACL is enforced.

Via the operator invalidation proxy (default, always available)

The proxy listens on port 8090 of the operator Service, validates the expression (only obj.http.* LHS; no wildcard-only), and forwards it to every pod via vinyl-agent POST /banvarnishadm ban <expr>:

POST http://<operator-svc>:8090/ban
Content-Type: application/json

{"expression": "obj.http.X-Cache-Tag ~ \"product-42\""}

Equivalent as native BAN HTTP method with the X-Ban-Expression header:

BAN http://<operator-svc>:8090/
X-Ban-Expression: obj.http.X-Cache-Tag ~ "product-42"

No opt-in needed. Proxy-side ACL enforcement is currently advisory (see “ACLs” below).

Directly to Varnish (BAN method on the traffic port)

From v0.4.2, VinylCache can expose a BAN handler directly in VCL, bypassing the operator proxy:

spec:
  invalidation:
    ban:
      enabled: true
      allowedSources:
        - "10.0.0.0/8"

The generator then emits a vinyl_ban_allowed ACL (localhost + operator pod IP + allowedSources) plus a vcl_recv BAN handler that calls std.ban(req.http.X-Vinyl-Ban):

BAN http://<cache-traffic-svc>:8080/
X-Vinyl-Ban: obj.http.x-url ~ "^/news/"

On malformed expressions the handler returns 400 Invalid ban expression: <std.ban_error()> rather than silently succeeding. When the header is missing, 400 Missing X-Vinyl-Ban header. Unauthorised source → 403 Forbidden.

Use obj.http.x-url / obj.http.x-host instead of req.* so the ban lurker can compact bans (req.* bans accumulate O(n*m)). The operator emits beresp.http.x-url / beresp.http.x-host on every cached object when ban.enabled: true is set (or xkey is enabled).

Xkey (surrogate-key)

Xkey (also called surrogate keys or cache tags) allows grouping objects under arbitrary string keys. When the cached response includes an Xkey: key1 key2 header, all objects with that key can be purged with a single request.

POST http://<operator-svc>:8090/purge/xkey
Content-Type: application/json

{"keys": ["product-42", "category-home"]}

The operator issues one PURGE with X-Xkey-Purge: <key> per key to every pod.

Xkey requires the vmod_xkey Varnish module. Enable it in the spec:

spec:
  invalidation:
    xkey:
      softPurge: true  # default

ACLs

There are two layers of access control, enforced at different points:

  • Proxy-side (spec.invalidation.purge.allowedSources, spec.invalidation.ban.allowedSources): the operator’s invalidation proxy checks the source CIDR before forwarding to pods. By default all sources are allowed — scope tightly in production.

  • Varnish-side (new in v0.4.2): the generated VCL contains vinyl_purge_allowed (always) and vinyl_ban_allowed (when ban.enabled: true). Both include 127.0.0.1 and the operator pod IP automatically; allowedSources CIDRs from the spec are appended. This is the ACL enforced in vcl_recv against the BAN/PURGE method coming directly to the traffic port.

In the common deployment — clients send PURGE/BAN to the proxy, the proxy forwards to Varnish — the operator’s pod IP is the only source Varnish ever sees, so the Varnish-side ACL is effectively a safety net. When direct-to-Varnish traffic is enabled, both layers apply.