Skip to content

perf(ai): parse the rule words only on a dictionary cache miss (#7829) - #7850

Merged
Aias00 merged 2 commits into
apache:masterfrom
konlue:fix/sensitive-word-parse-on-miss
Oct 19, 2026
Merged

Aias00 merged 2 commits into
apache:masterfrom
konlue:fix/sensitive-word-parse-on-miss

Conversation

@konlue

@konlue konlue commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Stacked on #7844 — this branch contains the #7830 dictionary-threading fix as its base, so the diff currently shows both changes; the #7830 portion will drop out of this diff automatically once #7844 merges. The actual change of this PR is the last commit (955652a).

Fixes #7829.

Summary

SensitiveWordPlugin#dictionary parses the rule words (split + contains dedup, O(n²)) before consulting the dictionary cache. On a cache hit the parsed words are never used, so every hit repeats the parse for nothing.

Modifications

  • Move the parseWords call into the cache-miss branch, the only place the rule words are consumed (redis merge and the redis-failure fallback).
  • Widen parseWords to package-private so a spy can pin the parse contract in tests.

Verifying this change

  • testCacheHitDoesNotParseTheRuleWords: warm the cache, then assert the second request never invokes parseWords. Fails on the previous code (NeverWantedButInvoked).

  • testCacheMissStillParsesTheRuleWords: a miss parses exactly once and the rule words are still enforced.

  • Targeted tests pass:

    ./mvnw -B -ntp -pl shenyu-plugin/shenyu-plugin-ai/shenyu-plugin-ai-sensitive-word test -Dtest=SensitiveWordPluginTest

    Full SensitiveWordPluginTest 20/20 green.

  • Checkstyle passes:

    ./mvnw -B -ntp -pl shenyu-plugin/shenyu-plugin-ai/shenyu-plugin-ai-sensitive-word checkstyle:check

    clean.

Notes

Miss/expiry/failure/fallback paths are unchanged; rule updates already evict the cache entry (SensitiveWordPluginDataHandler#removeHandle), so a rebuild re-parses fresh words. No measurable-gain claim beyond the removed work — the parse cost scales with the rule word count and vanishes entirely on hits.

@Aias00 Aias00 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved. Moving parseWords inside the cache-miss branch is the right fix and the gain is real: the cache-hit path runs on every request through the sensitive-word plugin, so an O(n²) parse of the rule words was being paid per request to produce a list that the hit path never reads.

I confirmed the variable is only consumed by the miss path — redisAutomaton(...) and the onErrorResume fallback that uses words are both inside that branch, so narrowing the scope does not orphan a reference.

The two tests are well aimed:

  • testCacheHitDoesNotParseTheRuleWords warms the dictionary, spies the plugin, and asserts parseWords is never called. Note this works precisely because the dictionary cache is process-wide, so the warmed entry is visible to the spy — that is the right thing to lean on rather than mocking it away.
  • testCacheMissStillParsesTheRuleWords covers the opposite direction, and importantly asserts the request is still blocked by the rule word (verify(chain, never()).execute(...)), so a regression where parsing is skipped and the word silently stops being enforced cannot pass.

Two notes, neither blocking:

  1. Merge order. This is stacked on #7844, so as long as #7850 lands after it the diff collapses to the one-line move. #7844 is already approved and green, so sequencing is enough — no need to rebuild the branch.

  2. parseWords visibility. It went from private to package-private purely so the spy can verify it. That is the same trade already made for redisAutomaton/ruleWordsAutomaton; if you want to keep the surface tighter, @VisibleForTesting on it would document the intent.

CI is still running on this branch — the retry-helper change from #7781 may need a re-run, but the affected module tests are green locally per the PR body.

@Aias00
Aias00 merged commit e1f9ea8 into apache:master Oct 19, 2026
28 checks passed
@Aias00 Aias00 added this to the 2.7.2 milestone Nov 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Task][Performance] Avoid reparsing rule words on sensitive-word dictionary cache hits

2 participants