pjfanning opened a new pull request, #1369:
URL: https://github.com/apache/pekko-http/pull/1369
### Motivation
A WebSocket connection whose network path is lost (e.g. a peer that
disappears without closing the TCP connection) can go unnoticed for a long
time. Periodic keep-alive Pings alone don't fail the connection when no Pong
comes back.
### Modification
- New settings `pekko.http.{server,client}.websocket.receive-idle-timeout`
and `send-idle-timeout`, default `infinite` (disabled). `WebSocketSettings`
gets `receiveIdleTimeout`/`sendIdleTimeout`, Java
`getReceiveIdleTimeout`/`getSendIdleTimeout`, and
`withReceiveIdleTimeout`/`withSendIdleTimeout` for Scala and
`java.time.Duration`, following the existing `periodicKeepAliveMaxIdle` pattern
(all `@since 2.0.0`).
- An idle-timeout layer in the WebSocket stack fails the flow when no frame
is received or sent within the configured time.
- Docs: `reference.conf`, plus an "Idle timeouts" section in the server and
client WebSocket pages.
- MiMa: new `websocket-idle-timeouts.excludes` for the abstract methods
added to the `@DoNotInherit` `WebSocketSettings`. Its license header is copied
from the sibling excludes files, since sbt's header plugin doesn't manage
`.excludes` files.
#### Differences from akka/akka-http#4289
- **Layer placement.** akka-http put the idle-timeout layer above
`frameHandling`. But `FrameHandler` drops incoming Pong frames, so Pong replies
to keep-alive Pings never reached it, and a connection that was idle but alive
timed out anyway. That defeats the "combine with
`periodic-keep-alive-max-idle`" use case. Here the layer sits directly above
masking, so every frame, Pings and Pongs included, counts as activity.
- **Exception type.** akka-http failed with `StreamIdleTimeoutException`.
Pekko's client TCP connection (`TcpIdleTimeout` in pekko-stream) rewrites any
`TimeoutException` heading to the network into `TcpIdleTimeoutException("TCP
idle-timeout ..., no bytes passed in the last 60 seconds")`, so a client
`send-idle-timeout` was reported as a TCP idle timeout. This PR adds
`WebSocketIdleTimeoutException` (a `RuntimeException`, `@since 2.0.0`), thrown
by a small private stage in both directions (downstream failure and upstream
cancellation), with a message naming the WebSocket setting and value.
- **Tests and setters.** akka-http needed separate spec classes to change
server settings through actor system config. With the `withX` setters, one spec
(`WebSocketIdleTimeoutSpec`) covers server and client in both directions, the
keep-alive case, and the settings themselves.
### Result
Users can detect lost WebSocket connections, e.g. by combining
`receive-idle-timeout` with `periodic-keep-alive-max-idle` in `ping` mode, as
long as the peer answers Pings.
### Tests
- `sbt "http-core/Test/testOnly
org.apache.pekko.http.impl.engine.ws.WebSocketIdleTimeoutSpec
org.apache.pekko.http.impl.engine.ws.WebSocketIntegrationSpec"`: 12 passed
(Scala 2.13); `WebSocketIdleTimeoutSpec`: 6 passed on Scala 3.3.8
- With the idle layer moved above frame handling (akka-http's placement),
the keep-alive test fails with `WebSocketIdleTimeoutException` (directional)
- `sbt http-core/mimaReportBinaryIssues`: pass
- `sbt docs/paradox`: pass
- `scalafmt --mode diff-ref=upstream/main`: no changes
### References
Port of akka/akka-http#4289 (Apache 2.0 now applies, since the Akka HTTP
10.6.0 license change date of 2026-10-23), with the differences above. The
tests in `WebSocketIdleTimeoutSpec` are adapted from that PR's tests.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]