-
Notifications
You must be signed in to change notification settings - Fork 967
Add streamTimeout option to WebSocketService/WebSocketClient; send close frame on inbound failure; clean up related resources #6357
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…uestLog, ensure close frame on cancel/abort; add tests (H2C close-frame/log, H1 channel close)
…utbound, closed outbound when inbound ends, introduced InboundCompleteException, and added a client-side newCloseWebSocketFrame() in WebSocketUtil.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall, left some comments
core/src/main/java/com/linecorp/armeria/common/stream/TimeoutStreamMessage.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/websocket/WebSocketServiceBuilder.java
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/client/websocket/WebSocketSession.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/client/websocket/WebSocketSession.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/client/websocket/WebSocketSession.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/client/websocket/WebSocketSession.java
Show resolved
Hide resolved
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #6357 +/- ##
============================================
- Coverage 74.46% 74.14% -0.33%
- Complexity 22234 23022 +788
============================================
Files 1963 2062 +99
Lines 82437 86177 +3740
Branches 10764 11317 +553
============================================
+ Hits 61385 63892 +2507
- Misses 15918 16872 +954
- Partials 5134 5413 +279 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
fix: In WebSocketSession endRequest -> requestCause
core/src/main/java/com/linecorp/armeria/client/websocket/WebSocketSession.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/common/stream/TimeoutStreamMessage.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/common/stream/TimeoutStreamMessage.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/internal/common/websocket/WebSocketUtil.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/internal/server/websocket/DefaultWebSocketService.java
Outdated
Show resolved
Hide resolved
… frame (#6375) Motivation: Currently, once an `HttpRequest` and `HttpResponse` is completed, the underlying HTTP2 stream is cancelled using a `RST_STREAM`. This makes sense for normal HTTP constructs since it indicates that we are no longer interested in the request, and we would like to release resources associated with it. However, some protocols such as WebSockets implement their own graceful shutdown procedure. In detail, Armeria's `HttpRequest`, `HttpResponse` implements WebSocket graceful shutdown and the reactive stream implementation is closed when a `CLOSE` frame is both sent and received. However, although the websocket session is completed, the underlying HTTP2 stream may not necessarily be complete. Protocol-wise, there is an inherent discrepancy between websocket session completion and HTTP2 stream completion. The current implementation defaults to sending a `RST_STREAM` immediately once the corresponding `HttpRequest` and `HttpResponse`. For websockets, I propose that a delay is given so that the remote has a chance to end the stream. Assuming that we will tie the lifecycle of inbound `WebSocket`s with outbound `WebSocket`s (so sending a close frame also closes the inbound) in #6357 , this option can be thought of similar to netty's `forceCloseTimeoutMillis` option. (which acts as a timeout since sending the CLOSE frame) Modifications: - Added a `closeHttp2StreamDelayMillis` option to `ServiceConfig` and relevant implementations - `WebSocketService` sets a `closeHttp2StreamDelayMillis` of 10 seconds by default - `HttpServerHandler` decides when to send a `RST_STREAM` based on the `closeHttp2StreamDelayMillis` - Added `Http2StreamLifecycleHandler` which maintains the lifecycle of reset futures. This ensures that scheduled futures aren't leaked for servers with high throughput. - Every time a request/response is closed but the corresponding stream is alive, `maybeResetStream` is called. - Every time a stream is closed, `notifyStreamClosed` is called to clean up possibly scheduled futures. Result: - Users can set a timeout for closing a websocket session - Fix a bug where closing a websocket session could send a `RST_STREAM` frame <!-- Visit this URL to learn more about how to write a pull request description: https://armeria.dev/community/developer-guide#how-to-write-pull-request-description -->
Motivation
StreamMessage.timeout(..., UNTIL_NEXT)
, expose it as an option onWebSocketServiceBuilder
/WebSocketClientBuilder
so both server and client can enable it consistently and easily.Modifications
Add
WebSocketServiceBuilder#streamTimeout(Duration)
.TimeoutStreamMessage
withStreamTimeoutMode.UNTIL_NEXT
insideDefaultWebSocketService#serve(...)
.Update
DefaultWebSocketService#serve(...)
:outbound.abort(mappedCause)
sorecoverAndResume
sends aCloseWebSocketFrame
.CancelledSubscriptionException
/AbortedStreamException
toInboundCompleteException
to avoid being skipped by the recovery logic.Add
WebSocketClientBuilder#streamTimeout(Duration)
.TimeoutStreamMessage
withStreamTimeoutMode.UNTIL_NEXT
insideDefaultWebSocketClient#connect(...)
.Update
WebSocketSession#setOutbound(...)
:recoverAndResume(...)
to outbound so that on send failure it emits aCloseWebSocketFrame
and records the exception inRequestLog
(endRequest(cause)
/endResponse(cause)
). ForClosedStreamException
, do not send a close frame—just abort.abort(...)
outbound with the mapped cause so the recovery stream kicks in.Add
InboundCompleteException extends CancellationException
:Add a client-side
newCloseWebSocketFrame(Throwable)
inWebSocketUtil
.Result
WebSocketService
/WebSocketClient
can applyStreamMessage.timeout(..., UNTIL_NEXT)
to inbound via the simplestreamTimeout(Duration)
option.ClosedStreamException
).RequestLog
.