Skip to content

fix(stream/traffic-split): handle upstream_id set by plugin in stream context#13285

Merged
nic-6443 merged 9 commits into
apache:masterfrom
nic-6443:fix/stream-traffic-split-upstream-id
Apr 24, 2026
Merged

fix(stream/traffic-split): handle upstream_id set by plugin in stream context#13285
nic-6443 merged 9 commits into
apache:masterfrom
nic-6443:fix/stream-traffic-split-upstream-id

Conversation

@nic-6443

Copy link
Copy Markdown
Member

When the traffic-split plugin selects an upstream via upstream_id, it sets api_ctx.upstream_id. In the HTTP path this is handled in handle_upstream() which re-fetches the upstream and updates api_ctx.matched_upstream. The stream path was missing this handling.

set_by_route() only checks api_ctx.upstream_conf (set when using inline upstream objects), but doesn't handle api_ctx.upstream_id. So even when the plugin selected a different upstream by ID, the route's original upstream was still used.

The fix adds a check after plugin.run_plugin("preread"): if api_ctx.upstream_id is set, fetch that upstream and update api_ctx.matched_upstream before calling set_upstream().

Also adds a test case that configures a stream route with a traffic-split rule using upstream_id and verifies traffic is correctly forwarded to the referenced upstream.

… context

When the traffic-split plugin selects an upstream via upstream_id, it sets
api_ctx.upstream_id. In the HTTP path this is handled in handle_upstream()
which re-fetches the upstream and updates api_ctx.matched_upstream. The stream
path was missing this: it called set_by_route() which only checks
api_ctx.upstream_conf (for inline upstream objects), leaving api_ctx.matched_upstream
pointing to the route's original upstream.

Fix: after plugin.run_plugin("preread"), if api_ctx.upstream_id is set, fetch
that upstream and update api_ctx.matched_upstream before calling set_upstream.
Copilot AI review requested due to automatic review settings April 23, 2026 09:25
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. bug Something isn't working labels Apr 23, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes stream (L4) routing so that when traffic-split (or another preread-phase plugin) selects an upstream via api_ctx.upstream_id, APISIX re-fetches that upstream and updates api_ctx.matched_upstream before calling upstream.set_by_route() / balancer selection—matching the HTTP-path behavior.

Changes:

  • In stream_preread_phase, after plugin.run_plugin("preread"), resolve api_ctx.upstream_id to an upstream object and update api_ctx.matched_upstream.
  • Add a stream test that configures traffic-split with weighted_upstreams[].upstream_id and verifies the request is forwarded to the referenced upstream.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
apisix/init.lua Applies plugin-selected upstream_id to stream routing by refreshing matched_upstream after preread plugins run.
t/stream-plugin/traffic-split.t Adds regression coverage for traffic-split selecting an upstream by upstream_id in stream context.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apisix/init.lua Outdated
- get_by_id() already logs the error when upstream is not found,
  so the extra core.log.error call was redundant; remove it
- delete earlier catch-all stream routes before upstream_id test
  to ensure route 3 is matched deterministically
@nic-6443

Copy link
Copy Markdown
Member Author

Applied same fix as #13284 TEST 5: added --- stream_enable to the route setup test to avoid stream→HTTP nginx restart after TEST 4's 10 concurrent connections.

@nic-6443

Copy link
Copy Markdown
Member Author

Fixed the nginx.conf parse error. The issue was that TEST 5 had both --- config (custom HTTP location for admin setup) and --- stream_enable. The test framework's preprocessors run in LIFO order, so Stream.pm runs last — it sees stream_config is defined (set by APISIX.pm) and appends a location = /t { sock:connect(...) } block after APISIX.pm's already large server config, producing a malformed nginx.conf. Since TEST 5 is just making HTTP admin API calls (create/delete routes), it doesn't actually need the stream server at all — removing --- stream_enable from that test fixes the issue.

@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Apr 23, 2026
@nic-6443
nic-6443 merged commit 64f3717 into apache:master Apr 24, 2026
19 checks passed
@nic-6443
nic-6443 deleted the fix/stream-traffic-split-upstream-id branch April 24, 2026 04:27
wistefan pushed a commit to wistefan/apisix that referenced this pull request Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants