fix(plugin): preserve plugin-conf state across consumer route merge - #13757
Open
AlinsRan wants to merge 1 commit into
Open
fix(plugin): preserve plugin-conf state across consumer route merge#13757AlinsRan wants to merge 1 commit into
AlinsRan wants to merge 1 commit into
Conversation
Several plugins cache request-time state on their conf object: ai-proxy-multi
keeps DNS resolution results (_dns_nodes, _nodes_ver, _resolved_endpoint),
upstream.lua keeps _nodes_ver, elasticsearch-logger keeps the probed _version.
merge_consumer_route deep-copies the whole route_conf, including value.plugins,
so every consumer request that misses the merged_route lru cache produces a
fresh plugin conf object and loses that cached state -- DNS is re-resolved, the
ES version is re-probed, and with multiple consumers the state is fragmented
per consumer instead of shared. Without consumer auth the route conf is never
copied, so this only regresses on the consumer path.
Adds an opts.shallow_prefix option to core.table.deepcopy that shallow-copies
members whose parent path starts with the given prefix, and uses
{ shallow_prefix = 'self.value.plugins' } in merge_consumer_route so the plugin
conf objects keep their identity. The plugins container itself is still a fresh
table, so overwriting its keys in the merge does not mutate the original; only
the plugin confs that carry state stay shared by reference, which restores the
non-consumer behavior.
Adds t/core/table.t TEST 13 for opts.shallow_prefix.
Signed-off-by: AlinsRan <alinsran@apache.org>
AlinsRan
force-pushed
the
perf/deepcopy-shallow-prefix
branch
from
July 29, 2026 14:03
49750c5 to
a16d026
Compare
There was a problem hiding this comment.
Pull request overview
This PR adjusts how route configuration is copied during merge_consumer_route so plugin configuration tables can retain request-time cached state (e.g., resolved DNS nodes or probed backend versions) across consumer-route merges, matching the non-consumer behavior where plugin conf identity is preserved.
Changes:
- Added a
shallow_prefixoption tocore.table.deepcopyto shallow-copy table members under a path prefix. - Updated
merge_consumer_routeto shallow-copyself.value.pluginsso plugin conf objects keep identity while still copying thepluginscontainer table. - Added a regression test covering
shallow_prefixbehavior int/core/table.t.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
apisix/core/table.lua |
Extends deepcopy with a prefix-based shallow-copy option to preserve selected subtree identities. |
apisix/plugin.lua |
Uses shallow_prefix = "self.value.plugins" when copying route conf during consumer merge to preserve plugin conf state. |
t/core/table.t |
Adds a test validating that shallow-prefix copying preserves nested table identity while allowing safe container overwrites. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
133
to
136
| local path = parent .. "." .. tostring(orig_key) | ||
| if opts and array_find(opts.shallows, path) then | ||
| if opts and (array_find(opts.shallows, path) or | ||
| (opts.shallow_prefix and str_has_prefix(parent, opts.shallow_prefix))) then | ||
| copy[orig_key] = orig_value |
Comment on lines
+821
to
+824
| -- the plugins subtree is fully overwritten below, so there is no need to | ||
| -- deep-copy it; shallow-copy that subtree to avoid the wasted work | ||
| local new_route_conf = core.table.deepcopy(route_conf, | ||
| { shallow_prefix = "self.value.plugins" }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Several plugins cache request-time state directly on their conf object:
ai-proxy-multi: DNS resolution results —instance_conf._dns_nodes,_nodes_ver,_resolved_endpoint,_healthy_dns_nodesupstream.lua:up_conf._nodes_verelasticsearch-logger: the probedconf._versionmerge_consumer_routedeep-copies the wholeroute_conf, includingvalue.plugins:So every consumer request that misses the
merged_routelru cache produces a fresh plugin conf object and loses that cached state — DNS is re-resolved, the ES version is re-probed, and with multiple consumers the state is fragmented per consumer instead of shared. Without consumer auth the route conf is never copied, so this only regresses on the consumer-auth path.This adds an
opts.shallow_prefixoption tocore.table.deepcopythat shallow-copies members whose parent path starts with the given prefix, and uses{ shallow_prefix = "self.value.plugins" }inmerge_consumer_routeso the plugin conf objects keep their identity.The
pluginscontainer itself is still a fresh table, so overwriting its keys during the merge does not mutate the original; only the plugin confs that carry state stay shared by reference — which restores the non-consumer behavior (a single source of truth for that route's plugin state).Which issue(s) this PR fixes
Plugin state cached on conf (DNS resolution, probed versions) is lost/re-computed on the consumer-auth path because of the plugins deep-copy.
Checklist
t/core/table.tTEST 13 for the option)