Add streamTimeout option to WebSocketService/WebSocketClient; send close frame on inbound failure; clean up related resources
Motivation
- Instead of asking each handler to wrap the inbound stream with
StreamMessage.timeout(..., UNTIL_NEXT), expose it as an option onWebSocketServiceBuilder/WebSocketClientBuilderso both server and client can enable it consistently and easily. - When the inbound completes abnormally (cancel/abort/timeout, etc.), further outbound sends are meaningless. We should immediately tidy up outbound and the stream/channel. If the connection is still valid and the termination is initiated locally, prefer sending a WebSocket close frame (with an appropriate status + reason) over a transport reset, for better reason propagation, interoperability, and observability.
Modifications
-
Add
WebSocketServiceBuilder#streamTimeout(Duration).- When set, wrap inbound in
TimeoutStreamMessagewithStreamTimeoutMode.UNTIL_NEXTinsideDefaultWebSocketService#serve(...).
- When set, wrap inbound in
-
Update
DefaultWebSocketService#serve(...):- If inbound completes with an error, call
outbound.abort(mappedCause)sorecoverAndResumesends aCloseWebSocketFrame. - Map
CancelledSubscriptionException/AbortedStreamExceptiontoInboundCompleteExceptionto avoid being skipped by the recovery logic.
- If inbound completes with an error, call
-
Add
WebSocketClientBuilder#streamTimeout(Duration).- When set, wrap inbound in
TimeoutStreamMessagewithStreamTimeoutMode.UNTIL_NEXTinsideDefaultWebSocketClient#connect(...).
- When set, wrap inbound in
-
Update
WebSocketSession#setOutbound(...):- Attach
recoverAndResume(...)to outbound so that on send failure it emits aCloseWebSocketFrameand records the exception inRequestLog(endRequest(cause)/endResponse(cause)). ForClosedStreamException, do not send a close frame—just abort. - When inbound completes exceptionally,
abort(...)outbound with the mapped cause so the recovery stream kicks in.
- Attach
-
Add
InboundCompleteException extends CancellationException:- Signals that inbound completed due to cancellation/abort.
-
Add a client-side
newCloseWebSocketFrame(Throwable)inWebSocketUtil.
Result
WebSocketService/WebSocketClientcan applyStreamMessage.timeout(..., UNTIL_NEXT)to inbound via the simplestreamTimeout(Duration)option.- When inbound completes with an error:
- If the channel is still usable, abort outbound with the mapped cause so a close frame is sent (skip sending for
ClosedStreamException). - Record request/response causes in
RequestLog. - On HTTP/1.x, close the channel; on HTTP/2, clean up the stream.
- If the channel is still usable, abort outbound with the mapped cause so a close frame is sent (skip sending for
🔍 Build Scan® (commit: 7315e5204428faa2651ae60d1989bfa1997cb2d2)
| Job name | Status | Build Scan® |
|---|---|---|
| build-ubicloud-standard-16-jdk-8 | ✅ | https://ge.armeria.dev/s/bm43lhrrpegnw |
| build-ubicloud-standard-16-jdk-21-snapshot-blockhound | ✅ | https://ge.armeria.dev/s/wcgst5gh5tzzm |
| build-ubicloud-standard-16-jdk-17-min-java-17-coverage | ❌ (failure) | https://ge.armeria.dev/s/4s265c27yqdgc |
| build-ubicloud-standard-16-jdk-17-min-java-11 | ✅ | https://ge.armeria.dev/s/35mkbdpex4q76 |
| build-ubicloud-standard-16-jdk-17-leak | ❌ (failure) | https://ge.armeria.dev/s/vswshzqvpsino |
| build-ubicloud-standard-16-jdk-11 | ✅ | https://ge.armeria.dev/s/nu3wjct2nb57c |
| build-macos-latest-jdk-21 | ✅ | https://ge.armeria.dev/s/2uuqvzlyy2bia |
Codecov Report
:x: Patch coverage is 80.00000% with 19 lines in your changes missing coverage. Please review.
:white_check_mark: Project coverage is 74.16%. Comparing base (8150425) to head (2184b0c).
:warning: Report is 215 commits behind head on main.
Additional details and impacted files
@@ Coverage Diff @@
## main #6357 +/- ##
============================================
- Coverage 74.46% 74.16% -0.30%
- Complexity 22234 23035 +801
============================================
Files 1963 2064 +101
Lines 82437 86188 +3751
Branches 10764 11317 +553
============================================
+ Hits 61385 63922 +2537
- Misses 15918 16859 +941
- Partials 5134 5407 +273
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
- :package: JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.