-
Notifications
You must be signed in to change notification settings - Fork 357
Description
The rSocket server initiates keep-alives right in the moment the client keep-alive is received and answered.
We have a client that announces in the SETUP frame to send keep-alives every 5 seconds. See https://rsocket.io/about/protocol/#setup-frame-0x01: "Time Between KEEPALIVE Frames: (31 bits = max value 2^31-1 = 2,147,483,647) Unsigned 31-bit integer of Time (in milliseconds) between KEEPALIVE frames that the client will send. Value MUST be > 0."
So the client sends a keep-alive to the server 5 seconds after the connection has been established. This keep-alive frame has the (R)espond flag set. See https://rsocket.io/about/protocol/#keepalive-frame-0x03: "KEEPALIVE frames MUST be initiated by the client and sent periodically with the (R)espond flag set. KEEPALIVE frames MAY be initiated by the server and sent upon application request with the (R)espond flag set."
The server responds with a keep-alive frame without the (R)espond flag set, which is correct AFAIK. But then, the server also sends a keep-alive frame with the (R)espond flag set. This is not entirely wrong, because the server is allowed to do so, as cited from the rSocket specification. But it really is not a good moment to do so. We just had the keep-alive roundtrip initiated by the client, so we know the connection is still alive. Why initiate another keep-alive from the server in that exact moment?
Here are some logs from the server to show what happens:
2025-11-12T09:43:46.799+01:00 DEBUG 26300 --- [ourServer] [ctor-http-nio-4] [] io.rsocket.FrameLogger : receiving ->
Frame => Stream ID: 0 Type: KEEPALIVE Flags: 0b10000000 Length: 14
Data:
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 00 00 00 00 00 00 00 |........ |
+--------+-------------------------------------------------+----------------+
2025-11-12T09:43:46.799+01:00 DEBUG 26300 --- [ourServer] [ctor-http-nio-4] [] io.rsocket.FrameLogger : sending ->
Frame => Stream ID: 0 Type: KEEPALIVE Flags: 0b0 Length: 14
Data:
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 00 00 00 00 00 00 00 |........ |
+--------+-------------------------------------------------+----------------+
2025-11-12T09:43:46.802+01:00 DEBUG 26300 --- [ourServer] [ parallel-6] [] io.rsocket.FrameLogger : sending ->
Frame => Stream ID: 0 Type: KEEPALIVE Flags: 0b10000000 Length: 14
Data:
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 00 00 00 00 00 00 00 |........ |
+--------+-------------------------------------------------+----------------+I tried to find out why the server shows this behavior. It seems to me like the server uses the value from the SETUP frame to time its initiation of keep-alives. So maybe this is a misinterpretation of that field in the SETUP frame. See this line in class RSocketServer: https://github.com/rsocket/rsocket-java/blob/master/rsocket-core/src/main/java/io/rsocket/core/RSocketServer.java#L452
Expected Behavior
The server should generally not initiate keep-alives on a regular basis. It should only send keep-alives when triggered by the application.
Actual Behavior
The server initiates keep-alives with the same rhythm as the client.
Steps to Reproduce
You can reproduce it by just running a server and connecting a client that announces keep-alives every 5 seconds in the SETUP frame. We are using the spring boot integration, so our server looks like this:
@Controller
public class RSocketController {
@ConnectMapping
public void connection() {
}
}Possible Solution
To me it seems like the field from the SETUP frame is not interpreted correctly. Maybe the lines that start the timer in the server that initiates keep-alives can just be removed?
Your Environment
- RSocket version(s) used: rsocket-core:1.1.5
- Other relevant libraries versions (eg.
netty, ...): We are using org.springframework.boot:spring-boot-starter-rsocket version 3.5.5 - Platform (eg. JVM version (
javar -version) or Node version (node --version)): Java 25 - OS and version (eg
uname -a):