This is an automated email from the ASF dual-hosted git repository.
shreemaan-abhishek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new 779948893 fix(graphql-proxy-cache): clear all Vary variants on PURGE
(#13523)
779948893 is described below
commit 779948893dd6cb2a64e8ad005bc4c68364d42a31
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Fri Jun 12 16:45:38 2026 +0800
fix(graphql-proxy-cache): clear all Vary variants on PURGE (#13523)
---
apisix/plugins/graphql-proxy-cache.lua | 6 +-
apisix/plugins/proxy-cache/memory_handler.lua | 6 ++
t/plugin/graphql-proxy-cache/memory.t | 104 ++++++++++++++++++++++++++
3 files changed, 114 insertions(+), 2 deletions(-)
diff --git a/apisix/plugins/graphql-proxy-cache.lua
b/apisix/plugins/graphql-proxy-cache.lua
index 2926471ec..3fb38311d 100644
--- a/apisix/plugins/graphql-proxy-cache.lua
+++ b/apisix/plugins/graphql-proxy-cache.lua
@@ -395,8 +395,10 @@ local function purge_hander()
end
os.remove(filename)
else
- local memory_handler = memory_strategy({shdict_name = conf.cache_zone})
- memory_handler:purge(ngx_var.upstream_cache_key)
+ local memory = memory_strategy({shdict_name = conf.cache_zone})
+ -- Walk the Vary index and purge every variant, not just the legacy
+ -- base-key entry, so PURGE clears all cached responses for the key.
+ memory_handler.purge_all_variants(memory, ngx_var.upstream_cache_key)
end
return core.response.exit(200)
diff --git a/apisix/plugins/proxy-cache/memory_handler.lua
b/apisix/plugins/proxy-cache/memory_handler.lua
index a106d8e09..cba8febef 100644
--- a/apisix/plugins/proxy-cache/memory_handler.lua
+++ b/apisix/plugins/proxy-cache/memory_handler.lua
@@ -571,4 +571,10 @@ function _M.body_filter(conf, ctx)
end
+-- Expose the variant-aware purge so callers reusing this strategy (e.g.
+-- graphql-proxy-cache's PURGE handler) can clear the index and every Vary
+-- variant instead of only the legacy base-key entry.
+_M.purge_all_variants = purge_all_variants
+
+
return _M
diff --git a/t/plugin/graphql-proxy-cache/memory.t
b/t/plugin/graphql-proxy-cache/memory.t
index 5545cef0c..bdda20f0a 100644
--- a/t/plugin/graphql-proxy-cache/memory.t
+++ b/t/plugin/graphql-proxy-cache/memory.t
@@ -553,3 +553,107 @@ a_1=MISS
a_2=HIT
b_1=MISS
b_2=HIT
+
+
+
+=== TEST 16: PURGE clears every Vary variant, not just the base key
+--- extra_yaml_config
+plugins:
+ - graphql-proxy-cache
+ - public-api
+--- http_config
+ lua_shared_dict memory_cache 50m;
+
+ server {
+ listen 1986;
+ server_tokens off;
+
+ location = /graphql {
+ content_by_lua_block {
+ ngx.header["Vary"] = "X-Variant"
+ ngx.say('{"data":{"variant":"', ngx.var.http_x_variant or
"none", '"}}')
+ }
+ }
+ }
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local http = require("resty.http")
+
+ local code, res_body = t('/apisix/admin/routes/gql-vary-purge',
ngx.HTTP_PUT, [[{
+ "uri": "/graphql",
+ "plugins": {
+ "graphql-proxy-cache": {
+ "cache_zone": "memory_cache",
+ "cache_strategy": "memory",
+ "cache_ttl": 300
+ }
+ },
+ "upstream": {
+ "nodes": {"127.0.0.1:1986": 1},
+ "type": "roundrobin"
+ }
+ }]])
+ if code >= 300 then
+ ngx.status = code
+ ngx.say(res_body)
+ return
+ end
+
+ local code = t('/apisix/admin/routes/graphql-purge', ngx.HTTP_PUT,
[[{
+ "uri": "/apisix/plugin/graphql-proxy-cache/*",
+ "plugins": {"public-api": {}}
+ }]])
+ if code >= 300 then
+ ngx.status = code
+ ngx.say("failed to set purge route")
+ return
+ end
+
+ local uri = "http://127.0.0.1:" .. ngx.var.server_port ..
"/graphql"
+ local body = '{"query":"query{persons{id}}"}'
+
+ local function fetch(variant)
+ local res, err = http.new():request_uri(uri, {
+ method = "POST",
+ body = body,
+ headers = {
+ ["X-Variant"] = variant,
+ ["Content-Type"] = "application/json",
+ },
+ })
+ if not res then
+ return nil, err
+ end
+ return res.headers["Apisix-Cache-Status"],
res.headers["APISIX-Cache-Key"]
+ end
+
+ -- Populate two distinct variants under the same base key.
+ local a1 = fetch("a")
+ local _, cache_key = fetch("a")
+ local b1 = fetch("b")
+ local b2 = fetch("b")
+ ngx.say("a_miss=", a1)
+ ngx.say("b_miss=", b1)
+ ngx.say("b_hit=", b2)
+
+ -- PURGE the base key once; the fix must clear both variants.
+ local purge_code =
t('/apisix/plugin/graphql-proxy-cache/memory/gql-vary-purge/'
+ .. cache_key, "PURGE")
+ ngx.say("purge=", purge_code)
+
+ -- Both variants must MISS again now that the index + variants are
gone.
+ ngx.say("a_after=", (fetch("a")))
+ ngx.say("b_after=", (fetch("b")))
+ }
+ }
+--- request
+GET /t
+--- response_body
+a_miss=MISS
+b_miss=MISS
+b_hit=HIT
+purge=200
+a_after=MISS
+b_after=MISS