App secret changes only invalidate cached clients on the node that saved them
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Description
App secret changes evict cached clients on the node that handled the save, and on no other node. On a cluster, the remaining nodes keep serving clients built with the previous credentials until their cache TTL expires.
AppsAPIImpl.save publishes the change with localSystemEventsAPI.asyncNotify(new AppSecretSavedEvent(...)). LocalSystemEventsAPI is node-local — there is no cluster propagation. Every subscriber therefore reacts on one node only:
AIAppListener→LangChain4jAIClient.flushCachesForHost(...), which clears the chat, streaming-chat, embedding and image model caches (Caffeine,maximumSize(128), 1-hour TTL, keyed byhost + ":" + providerConfigHash)AnalyticsAppListenerContentAnalyticsAppListener
Impact. After a credential rotation in the Apps portlet, a request routed to any other node can still be served by a model holding the old key for up to an hour. Where the rotation was a response to a leaked or revoked key, the revoked key stays in use on those nodes for that window. It also makes rotation non-deterministic to verify: whether the new key is in effect depends on which node answered.
Acceptance Criteria
- An app secret change invalidates the affected caches on every node in the cluster, not only the node that handled the save
- Covers all three current subscribers (
AIAppListener,AnalyticsAppListener,ContentAnalyticsAppListener), not just the AI one - Invalidation is scoped to the affected host rather than flushing every entry
- A test demonstrates that a secret change on one node evicts on another
Additional Context
- Found during review of #37559 by @wezell, who asked whether these caches need cluster-wide invalidation. They do.
- Pre-existing behaviour — not introduced by #37559. That PR reuses the existing listener and flush deliberately, so that a second cache could not keep serving a revoked key; the
:inferencecache keys it adds are covered by the existing host-prefix flush. AppsAPIImplpublish site:localSystemEventsAPI.asyncNotify(new AppSecretSavedEvent(...))- Flush implementation:
LangChain4jAIClient.flushCachesForHost(String)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the AppsAPIImpl publish site and trace LocalSystemEventsAPI, AppSecretSavedEvent, AIAppListener, AnalyticsAppListener, ContentAnalyticsAppListener, and LangChain4jAIClient.flushCachesForHost(String). Review how events cross cluster nodes and how the host-scoped caches are flushed. Done means a secret change on one node invalidates the affected caches on another, all three subscribers are covered, and a test demonstrates this behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend, distributed-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 64/100