You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
SocketAcceptorInterceptor receive an unexpected payload object rather than receive a setup payload object #970
We create a client and server with reconnection feature. The server register a interceptor to receive the setup payload and then deserialized for authentication.
Client have another daemon thread called Thread A and send data by rsocket periodically. The sended payload data we call it payload-A.
After server is stopped and we can see the priodically sended data is failed as what we expected. After the server is started again, client begin to reconnect to the server. We can see the socket acceptor receive the setup payload data, but it is not the setup data we generated by method getAuthInfo() method. The server sidecar acceptor receive an unexpected normal payload data which is very strange.
Related server and client code:
// client requesterMono = rsocketRequesterBuilder.setupRoute(SETUP_ROUTE)
.setupData(newObjectMapper().writeValueAsString(getAuthInfo()))
.dataMimeType(MimeTypeUtils.parseMimeType(WellKnownMimeType.APPLICATION_JSON.getString()))
.rsocketConnector(connector -> connector.acceptor(responder).fragment(MTU_BYTE_SIZE)
.keepAlive(Duration.ofSeconds(KEEP_ALIVE_INTERVAL_SEC), Duration.ofSeconds(KEEP_ALIVE_MAX_TIME_SEC))
.reconnect(Retry.fixedDelay(Integer.MAX_VALUE, Duration.ofSeconds(RSOCKET_RETRY_INTERVAL_SECONDS))
.doAfterRetry(retrySignal -> log.warn("RSocket client is reconnecting to get the newest connection...."))))
.connect(TcpClientTransport.create(TcpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, TCP_CONN_TIMEOUT)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.SO_KEEPALIVE, true)
.host(consoleDomain)
.port(SERVER_PORT)
.secure(ssl -> ssl.sslContext(sslContext))));
// register a socket acceptor interceptor to receive the authentication setup payload object in the server sideprotectedSocketAcceptorInterceptorgenAcceptorAuthInterceptor() {
SocketAcceptorInterceptorinterceptor = acceptor -> (setup, sendingSocket) -> {
try {
log.info("receive an task connection try to init.");
LocalTaskAuthInfoauthInfo = newObjectMapper().readValue(setup.getDataUtf8(), LocalTaskAuthInfo.class);
//ignore some non-related code...returnacceptor.accept(setup, sendingSocket);
} catch (Exceptione) {
StringerrMsg = "try to accept a connection error.msg:" + ExceptionUtils.getRootCauseMessage(e);
log.warn(errMsg, e);
exceptionService.saveException(newSidecarRuntimeException(e));
returnMono.error(newRSocketAuthException(errMsg));
}
};
returninterceptor;
}
//serverRSocketServer.create(routeHandler.responder()).fragment(RSocketConnConstans.MTU_BYTE_SIZE)
.interceptors(registry -> registry.forSocketAcceptor(interceptor))
.bind(TcpServerTransport.create(TcpServer.create()
.option(EpollChannelOption.SO_KEEPALIVE, true)
.option(EpollChannelOption.TCP_NODELAY, true)
.secure(ssl -> ssl.sslContext(sslContext))
.port(Integer.valueOf(consoleConfig.getRsocketConsolePort()))
.doOnConnection(
t -> log.info("New sidecar CONNECTED. Pay attention that this is maybe a resumed connection..."))))
.subscribe();
Expected Behavior
Receive setup payload in the socket acceptor
Actual Behavior
Receive a normal payload data.
Steps to Reproduce
Unfortuncately that we can't reproduce it stablely. The issue occur sometimes after server is restarted. Usually after the server is restarted everything goes well.
Possible Solution
May be this is a parallel bug. It occur now and then. I know this issue may ba a little difficult. Is there any suggestion that I can take to set the breakpoint. This issue's key point is to find out why the normal paryload data replace the setup payload data and then cause the deserialization problem.
Your Environment
RSocket version(s) used: rsocket-core-1.0.2 and springboot-starter-rsocket 2.3.4.RELEASE
Platform (eg. JVM version (javar -version) or Node version (node --version)): OpenJDK 1.8
@OlegDokuka Thanks, I will try to upgrade our rsocket version to check whether this issue will happen again. However, I still have some confusion. I checked the issue #842 and find its problem is the cnf count is 0 when reconnecting. His case seems can be reproduced always. My case have some difference because the issue happen now and then. Can you tell me the bug's mechanism and in what situation it will happen? I want to ensure that my issue is caused by the related bug.
@OlegDokuka I updateed my issue. I checked that my rsocket-core version is 1.0.2 and the mentioned bug is fixed. So I think my probleam is not caused by mentioned bug in #842 . Can you give any idea that where I can set the breakpoint to capture the moment when setupPayload is not an object instance of ConnectionSetupPayload. I can set the breakpoint to check why during reconnection my server will receive a non-setup payload contents.
@OlegDokuka To get more information. Would you mind telling me where to set the breakpoint when reconnection haapen and the setup payload is set? I now set the breakpoint in RSocketConnector class's method setupPayload and I find I can't capture any case that I receive a ConnectionSetupPayload.
@KaimingWan is it still an issue for you? If so, can you try to reproduce that issue with a pure rsocket setup (I mean your example uses spring-messaging rsocket, however, to minimize the possible error surface, I need to make sure that you observe the same problem with vanilla rsocet-java)
@OlegDokuka Sorry for the late response. The issue happens now and then. Recently I meet the issue again and I put forward the issue here: spring-projects/spring-framework#26626 . May be a little more detailed than this issue I created before. I will try to write an example to show what is going on. But the issue may not happen every time, the example may not reproduce what I met. However, another issue always happen is that the first stream frame log that carry setup payload info is missing when client connect to server. As I expected, the first stream should carry the setup payload and been sent to SETUP_ROUTE( route name is "conn-setup") in my case, but I didn't see any logs. Later I will give an example here.
@OlegDokuka I write a simple example but it seems everything goes well. The first frame carry the setup payload is print out normally. Where to set the break point if I want to debug my real world code. BTW, my test example is as follow:
@KaimingWan we had a chat with @rstoyanchev and it can be that this is spring-messaging issue and the fact that the given DTO can be modified (at least that is what I understood from your comments on the linked issue) which means the spring codecs which coverts given object to ByteBuf may provide a corrupted one.
@OlegDokuka Thanks for your information. In my case, not only the given setup payload is truncated and it is also be replaced by another dto's value. It seems more like an issue caused by concurrency. In my real world code, I try to ensure there is no other send request when rsocket is reconnecting. You said it may caused by spring-messaging's process. Are there any advice about where to set the breakpoint? Another clus is clear that in my real world code, every time I restart the client I can find the first stream is missing.
I debug my code and especially pay attention to the code from spring-messaging. I find after connected, the spring-rsocket only return a requester object and will not send setup payload to the remote
@KaimingWan after some more looking, we found the problem. The fix is available in snapshots. Not sure if you're able to confirm the fix with 1.0.4-SNAPSHOT via https://oss.jfrog.org/artifactory/oss-snapshot-local -- that would be very helpful, but either way this fix should help to address the issue.
@rstoyanchev Thanks for your work. Because the issue occur in our real world code, so I can't use the snapshot directly in the production environment. However, I will try to use the snapshot in my develeopment environment and see whether the issue will happen again. Are there any plan about when 1.0.4 release? BTW, it the following commit fix this issue? Would you mind telling me what is the key point of this fix? I still do not know in what situation the payload will be corrupted and why after receive the corrupted payload, rsocket will keep retrying.
@KaimingWan The issue was in the DefaultPayload.create(ByteBuf, ByteBuf) method, which internally did only ByteBuf#nioBuffer which returned access to shared memory without copying it. That said, when given ByteBuf is released, the shared NIO ByteBuffer can be easily corrupted. That is basically what you have seen. With the #993, we ensured that content is really copied so no corruption should occur
@OlegDokuka Thanks for your explanation. I find 1.0.4 has been released yesterday and we have changed to this version. Respect for you guys's efficient work~
Activity
OlegDokuka commentedon Dec 30, 2020
@KaimingWan it looks like you are observing an already fixed bug (please see #842).
Can you please check if the same is reproducing with 1.0.3 or 1.1.0?
KaimingWan commentedon Dec 31, 2020
@OlegDokuka Thanks, I will try to upgrade our rsocket version to check whether this issue will happen again. However, I still have some confusion. I checked the issue #842 and find its problem is the cnf count is 0 when reconnecting. His case seems can be reproduced always. My case have some difference because the issue happen now and then. Can you tell me the bug's mechanism and in what situation it will happen? I want to ensure that my issue is caused by the related bug.
KaimingWan commentedon Dec 31, 2020
@OlegDokuka I updateed my issue. I checked that my rsocket-core version is 1.0.2 and the mentioned bug is fixed. So I think my probleam is not caused by mentioned bug in #842 . Can you give any idea that where I can set the breakpoint to capture the moment when setupPayload is not an object instance of ConnectionSetupPayload. I can set the breakpoint to check why during reconnection my server will receive a non-setup payload contents.
KaimingWan commentedon Jan 4, 2021
@OlegDokuka To get more information. Would you mind telling me where to set the breakpoint when reconnection haapen and the setup payload is set? I now set the breakpoint in RSocketConnector class's method setupPayload and I find I can't capture any case that I receive a ConnectionSetupPayload.
KaimingWan commentedon Jan 4, 2021
@OlegDokuka Now I set breakpoint in RSocketServer's acceptSetup method. I will give more info if I encounter this issue again.
OlegDokuka commentedon Jan 20, 2021
@KaimingWan is it still an issue for you? If so, can you try to reproduce that issue with a pure rsocket setup (I mean your example uses spring-messaging rsocket, however, to minimize the possible error surface, I need to make sure that you observe the same problem with vanilla rsocet-java)
KaimingWan commentedon Mar 2, 2021
@OlegDokuka Sorry for the late response. The issue happens now and then. Recently I meet the issue again and I put forward the issue here: spring-projects/spring-framework#26626 . May be a little more detailed than this issue I created before. I will try to write an example to show what is going on. But the issue may not happen every time, the example may not reproduce what I met. However, another issue always happen is that the first stream frame log that carry setup payload info is missing when client connect to server. As I expected, the first stream should carry the setup payload and been sent to SETUP_ROUTE( route name is "conn-setup") in my case, but I didn't see any logs. Later I will give an example here.
KaimingWan commentedon Mar 2, 2021
@OlegDokuka I write a simple example but it seems everything goes well. The first frame carry the setup payload is print out normally. Where to set the break point if I want to debug my real world code. BTW, my test example is as follow:
test acceptor is :
The log is :

OlegDokuka commentedon Mar 2, 2021
@KaimingWan we had a chat with @rstoyanchev and it can be that this is spring-messaging issue and the fact that the given DTO can be modified (at least that is what I understood from your comments on the linked issue) which means the spring codecs which coverts given object to ByteBuf may provide a corrupted one.
Thus, not sure it is rsocket-java issue
Ensure setupPayload is actually copied
1 remaining item
KaimingWan commentedon Mar 3, 2021
@OlegDokuka Thanks for your information. In my case, not only the given setup payload is truncated and it is also be replaced by another dto's value. It seems more like an issue caused by concurrency. In my real world code, I try to ensure there is no other send request when rsocket is reconnecting. You said it may caused by spring-messaging's process. Are there any advice about where to set the breakpoint? Another clus is clear that in my real world code, every time I restart the client I can find the first stream is missing.
KaimingWan commentedon Mar 3, 2021
Is keep alive frame have relation with this issue? I debug my code and find the first stream can be printed out during my step by step debug.

KaimingWan commentedon Mar 3, 2021
I debug my code and especially pay attention to the code from spring-messaging. I find after connected, the spring-rsocket only return a requester object and will not send setup payload to the remote


DefaultPayload#create properly copies ByteBuf content
DefaultPayload#create properly copies ByteBuf content
DefaultPayload#create properly copies ByteBuf content
rstoyanchev commentedon Mar 3, 2021
@KaimingWan after some more looking, we found the problem. The fix is available in snapshots. Not sure if you're able to confirm the fix with
1.0.4-SNAPSHOTvia https://oss.jfrog.org/artifactory/oss-snapshot-local -- that would be very helpful, but either way this fix should help to address the issue.KaimingWan commentedon Mar 4, 2021
@rstoyanchev Thanks for your work. Because the issue occur in our real world code, so I can't use the snapshot directly in the production environment. However, I will try to use the snapshot in my develeopment environment and see whether the issue will happen again. Are there any plan about when 1.0.4 release? BTW, it the following commit fix this issue? Would you mind telling me what is the key point of this fix? I still do not know in what situation the payload will be corrupted and why after receive the corrupted payload, rsocket will keep retrying.
OlegDokuka commentedon Mar 4, 2021
@KaimingWan The issue was in the
DefaultPayload.create(ByteBuf, ByteBuf)method, which internally did onlyByteBuf#nioBufferwhich returned access to shared memory without copying it. That said, when givenByteBufis released, the shared NIOByteBuffercan be easily corrupted. That is basically what you have seen. With the #993, we ensured that content is really copied so no corruption should occurKaimingWan commentedon Mar 5, 2021
@OlegDokuka Thanks for your explanation. I find 1.0.4 has been released yesterday and we have changed to this version. Respect for you guys's efficient work~