[BUG] WebSocket endpoint re-registered before markRegistered guard — duplicate endpoint registration crashes context refresh
- Dominant language
- Java
- Stars
- 8.8k
- Forks
- 3.1k
- Avg merge
- 7d 1h
- Merged PRs (30d)
- 85
Description
- Severity: Medium
- Location:
`shenyu-client/shenyu-client-websocket/shenyu-client-spring-websocket/src/main/java/org/apache/shenyu/client/spring/websocket/init/SpringWebSocketClientEventListener.java:113-115` (`registerEndpointsBeans` call in `getBeans`); guard at `shenyu-client-core/.../AbstractContextRefreshedEventListener.java:149` (`markRegistered`)
-
Description:
The parent `onApplicationEvent` calls `getBeans(context)` (line 145) **before** `markRegistered()` (line 149). The WebSocket override of `getBeans` performs the side-effecting `registerEndpointsBeans(context, endpointBeans)` (line 114), which calls `ShenyuServerEndpointerExporter.registerEndpoint` → `serverContainer.addEndpoint(endpointConfig)` for every `@ShenyuServerEndpoint` bean. The once-only `markRegistered` guard protects `handle` and URI publishing, but does **not** protect this `getBeans` side effect. On a second `ContextRefreshedEvent` (Spring MVC parent+child contexts, or integration tests refreshing multiple contexts), `addEndpoint` is invoked again for the same path; per the Jakarta WebSocket spec and Tomcat's `WsServerContainer`, re-adding a duplicate path throws `DeploymentException` (wrapped as `IllegalStateException` at `ShenyuServerEndpointerExporter.java:112`), failing the context refresh.
-
Impact:
Duplicate websocket endpoint registration crashes context refresh in hierarchical/multi-refresh contexts.
-
Suggested fix:
Move `registerEndpointsBeans` out of `getBeans` into `handle` (which is post-guard), or track endpoint registration with its own `AtomicBoolean`.
-
Confidence: Medium
---
_Identified during the 2026-08-02 deep re-scan; full list in [`docs/scan2-2026-08-02/06-medium-tiers.md`](docs/scan2-2026-08-02/06-medium-tiers.md)._
Contributor guide
No contributing guide indexed for this repository
Research direction
Read AbstractContextRefreshedEventListener.java around markRegistered and SpringWebSocketClientEventListener.java around getBeans and registerEndpointsBeans. Trace the call into ShenyuServerEndpointerExporter.java:112, then reproduce or inspect a second ContextRefreshedEvent. Done means repeated refreshes no longer invoke duplicate endpoint registration or fail with a DeploymentException/IllegalStateException.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100