Cache statuses
Every response that went through the cache carries a gp-cache header with one of four
values: HIT, MISS, PASS or STALE. It tells you what the cache did with the
request without opening a log, so it is the first thing to check when you want to know whether
your caching rules apply.
A few things about the header itself:
- GraphPilot removes the
x-cacheandx-cache-hitsheaders Fastly (the edge network GraphPilot runs on) adds, sogp-cacheis the only cache status on a response. - It can be switched off with
response.cache_headers = false. Most troubleshooting reads it, so a common pattern is to leave it on in a staging service and switch it off in production. - A request refused before the cache (a
401from authentication, for example) carries nogp-cacheheader. - A service that runs in lean mode sends no
gp-cacheheader on responses the cache would otherwise have looked up, because edge caching is withdrawn. A request that bypasses the cache still reportsPASSwith its reason.
All response headers GraphPilot sets are listed in the headers reference.
Cache HIT
Section titled “Cache HIT”The response came from the cache. A stored entry matched the request and was still fresh, so
your origin was not asked. A HIT carries no gp-cache-reason.
Cache MISS
Section titled “Cache MISS”No usable entry existed, so the request went to your origin, and the response was stored.
The next matching request at the same edge location can be a HIT. A MISS happens the first
time an operation runs at a location, after an entry expires, and after a purge.
A MISS never carries gp-cache-reason. If the response was not stored, for whatever reason,
the status is PASS.
Cache PASS
Section titled “Cache PASS”A PASS means nothing was stored. The response came from your origin and was delivered to
the client in full, but no cache entry answered the request and none was written. Every PASS
carries gp-cache-reason, and the prefix of that code tells you where it was decided.
The cache was never consulted (CACHE_PASS_*). No lookup happened. This is decided before
anything about the request is parsed, so it says nothing about the response: a
bypass expression matched, the request was a
WebSocket upgrade or used a method you never cache, a client profile takes the caller off the
cache, and a few more. Every code is on the cache was not
consulted.
The response was not stored (CACHE_SKIPPED_*). Usually the cache was looked up and missed,
the request went to your origin, and then the request or the response ruled storing out: a
mutation, a Set-Cookie, a no-store, no freshness lifetime, a GraphQL error. Two codes do not
fit that pattern: CACHE_SKIPPED_ENTRY_NOT_REPLACED, where the lookup found an entry this request
did not use, and CACHE_SKIPPED_NO_ORIGIN_RESPONSE, where no response came back from your origin
at all. A few of these codes are
faults on GraphPilot’s side rather than properties of your response, and they are still a
PASS, because nothing was stored. Every code is on the response was not
cached, and the order they are decided in is
on when a response is cached.
A 4xx or 5xx response from your origin is also a PASS, with CACHE_SKIPPED_ERROR_STATUS,
unless its status is listed in cache.policy.store_error_statuses. A GraphQL response that is not
JSON GraphPilot can parse is delivered unchanged and not stored, with
CACHE_SKIPPED_UNPARSEABLE_GRAPHQL_RESPONSE.
In Insights, both kinds of code are one column and one filter, Not cached because, grouped by who can act on the reason. The request’s Cache tab still says whether the cache was consulted before the decision.
Cache STALE
Section titled “Cache STALE”The response came from the cache although the entry had passed its freshness lifetime, because it was still inside a stale window. The client got the stored answer immediately, and GraphPilot asked your origin for a fresh copy in the background. That background response goes through the normal store decision.
How long the window is, where it comes from and what switches it off is on stale
windows. A MISS inside the window is possible too, when the request
is handled by a cache server that does not hold the entry; see stale responses within a
location.
Why a response was not cached
Section titled “Why a response was not cached”gp-cache tells you what happened. On a PASS, a second header, gp-cache-reason, tells
you why:
gp-cache: PASSgp-cache-reason: CACHE_SKIPPED_SET_COOKIEgp-cache-reason appears only on a PASS:
- with a
CACHE_PASS_*code, the cache was never consulted. - with a
CACHE_SKIPPED_*code, the request reached your origin, the answer came back, and it was not stored.
A HIT, MISS or STALE carries no reason, because there is nothing to explain. A MISS is
itself the signal that the entry was written and the next matching request at that location
should be a HIT.
Which status a refused store reports
Section titled “Which status a refused store reports”Every CACHE_SKIPPED_* code arrives with gp-cache: PASS, never with MISS. Every code, with
what to do about it, is in the codes reference.
The value of gp-cache-reason is a stable code, not prose. The same code appears in your logs
on the same request, so you can start from either end: notice the header in a browser’s network
tab and search your logs for the code, or the reverse. gp-cache itself stays one of HIT,
MISS, PASS or STALE and never carries the reason, so anything matching on it is unaffected.