Debugging surrogate keys
Invalidation only reaches what the keys name, so “which keys did this response get” is the question behind most invalidation problems. You can read the answer off any response.
The gp-surrogate-key response header
Section titled “The gp-surrogate-key response header”With response.surrogate_key_header = true (it is off by default), every response that carries
keys lists them, space separated. The header grows with the response, one key per object with an
entity key, so switch it on where you want to inspect keys, for example in a staging service:
# GRAPHPILOT_HOST is your service hostname, <subdomain>.<label>.graphpilot.cloud,# or a custom domain you attached. The portal lists both.curl -sS -D- -o/dev/null "https://$GRAPHPILOT_HOST/products/42" | grep -i '^gp-surrogate-key'gp-surrogate-key: ck:GET:/products/42 product-42 catalogFor a GraphQL request, the keys GraphPilot derived from the response are listed too:
curl -sS -D- -o/dev/null "https://$GRAPHPILOT_HOST/graphql" \ -H 'content-type: application/json' \ -d '{"query":"{ products { id name } }"}' | grep -i '^gp-surrogate-key'gp-surrogate-key: ck:9f86d0 ck:9f86d0:4e0740 q:products Product Product:id:1 Product:id:2This is the set the entry was tagged with, which is exactly the set a purge can name to remove
it. The header stops at 8,192 bytes by default (response.surrogate_key_header_max_bytes). If a gp-surrogate-key-truncated header is also present, the
list is incomplete and that header says how many keys were left out. The request detail in the
portal has the full set. See size limit. Before raising the
limit, check what every client in the path accepts, including proxies and load balancers in front
of your clients: a header they refuse fails the whole request, not just the header.
Reading the keys
Section titled “Reading the keys”The prefix tells you what kind of key it is, and the kind decides what invalidation can do with
it: ck: is the cache key, q: and m: name an operation, ![…] an empty list, and
Type:field:value one object. The full table, with what each kind lets a purge do, is on
surrogate keys.
What to check
Section titled “What to check”Your origin’s keys are there. A key your origin sent in a Surrogate-Key header appears in
its folded form: a character outside printable ASCII is folded (Müller as Muller), so look
for that spelling. See the header’s format.
The deployment accepted your directives. A @surrogateKey the deployment build refused
contributes no key, and the deployment still succeeds. Read its
diagnostics after
every schema change.
Your entity keys are there at all. If a response holding products carries only Product
and q:products and no Product:id:…, GraphPilot found no key field. Either the type has no
inferable key or the field is not annotated. Fix it in the schema, not in the query: you do not
need to select the key fields yourself, selection set
expansion injects them and strips them again.
They name the type you expect. For an interface or union, the key uses the concrete type
that was actually returned. A key reading Product:id:1 where you expected Item:id:1 means
the invalidation you write against Item will miss it.
They are stable across requests. The same object in two different queries must produce the same key, or a purge that clears one will not clear the other. If they differ, the key fields being read differ, which usually means one query reaches the object through a different parent field.
When the keys do not fit
Section titled “When the keys do not fit”No key is ever silently dropped. If a response’s keys do not fit on the cache entry, the response
is not cached at all, reported as CACHE_SKIPPED_SURROGATE_KEYS_TOO_LARGE, so a purge can
never miss an entry because a key went missing from it. A response that generates that many keys
is usually a very large list; paginating it fixes both problems at once. See how many keys fit
on one response.
In the portal
Section titled “In the portal”When a request is stored in Insights (part of every plan, within its
logged-request allowance), the same keys are recorded with it. The
request detail in the portal shows them on every plan, and from Airliner (Business) you can
filter the request list by a key. The list has no surrogate key column. From the CLI,
gpilot requests --wide shows them (from Airliner (Business)), and --surrogate-key finds the
requests that carried one.
The service’s Purges page lists every purge with the keys it addressed. Together, the two answer “what did that purge actually remove” after the fact, without reproducing the request. See verifying a purge.
Related
Section titled “Related”- Surrogate keys: the kinds of key and what they may contain
- The Surrogate-Key header: keys from your origin
- Headers: every header GraphPilot sets
- Troubleshooting: start from a symptom