Skip to content

Conversation

@richmeyer7
Copy link

In spring-messaging-5.2.5-RELEASE, I observed in the debugger that to successfully complete the connection setup after intercepting and caching a Server Requester, the Kotlin @ConnectMapping method must declare a return type of Mono? and then return null.
Any other declared return type or a non-null return value, including Mono.empty(), caused AbstractEncoderMethodReturnValueHandler.handleReturnValue(...) to fall through to the code after this if block:

		if (returnValue == null) {
			return handleNoContent(returnType, message);
		}

and that resulted in a failure to establish the connection with a RejectedSetupException.

In spring-messaging-5.2.5-RELEASE, I observed in the debugger that to successfully complete the connection setup after intercepting and caching a Server Requester, the Kotlin @ConnectMapping method must declare a return type of Mono<Void>? and then return null.
Any other declared return type or a non-null return value, including Mono.empty(), caused AbstractEncoderMethodReturnValueHandler.handleReturnValue(...) to fall through to the code after this `if` block:

```
		if (returnValue == null) {
			return handleNoContent(returnType, message);
		}
```
and that resulted in a failure to establish the connection with a RejectedSetupException.
@pivotal-issuemaster
Copy link

@richmeyer7 Please sign the Contributor License Agreement!

Click here to manually synchronize the status of this Pull Request.

See the FAQ for frequently asked questions.

@pivotal-issuemaster
Copy link

@richmeyer7 Thank you for signing the Contributor License Agreement!

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label May 7, 2020
@rstoyanchev
Copy link
Contributor

From the reference docs:

Keep in mind that @ConnectMapping methods are essentially handlers of the SETUP frame which must be handled before requests can begin. Therefore, requests at the very start must be decoupled from handling.

In other words the completion of a @ConnectMapping method cannot be tied to the start of a request. Please, provide details on what does your method look like.

@rstoyanchev rstoyanchev added the status: waiting-for-feedback We need additional information before we can continue label May 12, 2020
@richmeyer7
Copy link
Author

richmeyer7 commented May 12, 2020 via email

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels May 12, 2020
@rstoyanchev
Copy link
Contributor

rstoyanchev commented May 22, 2020

@richmeyer7, replying through email doesn't support markdown and doesn't work very well for code samples (see above).

I'm pasting your sample here as best as I could extract it.

private val backendServiceRsocketRequesterReplayProcessors:
    ConcurrentHashMap<String, ReplayProcessor<RSocketRequester> = ConcurrentHashMap()

@ConnectMapping("ApiService.registerBackendService")
@MessageMapping("ApiService.registerBackendService")
suspend fun registerBackendService(@Payload name: String, rSocketRequester: RSocketRequester): Mono<Void> {
    backendServiceRSocketRequesterReplayProcessors
            .computeIfAbsent(name) { ReplayProcessor.cacheLast() }
            .onNext(rSocketRequester)

    return null // This is the only value I found that doesn't trigger RejectedSetupException.
}

I don't know if having both @ConnectMapping and @MessageMapping is intentional. Are you intercepting both connection opening and a request with the same method?

That aside the method works without a return value if suspend is removed. Do you really mean for this to use coroutines here?

@rstoyanchev rstoyanchev added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels May 22, 2020
@sdeleuze
Copy link
Contributor

If you want to translate a Reactive method that returns Mono<Void> to Coroutines, you should use suspend fun registerBackendService(@Payload name: String, rSocketRequester: RSocketRequester) { ... }, not suspend fun registerBackendService(@Payload name: String, rSocketRequester: RSocketRequester): Mono<Void> { ... } which is conceptually a Mono<Mono<Void>> Reactive return value.

@richmeyer7
Copy link
Author

@rstoyanchev -
Thank you for extracting my sample, Rossen. I inadvertently replied through email.
I see only one discrepancy, that my sample return type was actually Mono<Void>? (nullable).

I had the @MessageMapping because I had multiple connecting services, and needed each connecting service to provide a name that my code used to keep track of which cached RSocketRequester was connected to which service. In case that is a problem, I have now removed @MessageMapping. My architecture has changed to a single connecting service.

I used a suspend fun because that is what the Kotlin example shows in the referenced documentation.

I retested without the suspend and with no return type, and the connection now succeeds. Here is the successful method:

@ConnectMapping()
   fun registerApiService(rSocketRequester: RSocketRequester) {
      apiServiceRSocketRequesterReplayProcessor.onNext(rSocketRequester)
      GlobalScope.launch {
         // TODO: Send all faults (non-periodic state) to the ApiService.
      }
   }

With suspend and no return type as shown in the existing documentation, the connection always fails with RejectedSetupException: Missing 'rsocketResponse'. Here is the failing method:

@ConnectMapping() // Always fails with "suspend":
   suspend fun registerApiService(rSocketRequester: RSocketRequester) {
      apiServiceRSocketRequesterReplayProcessor.onNext(rSocketRequester)
      GlobalScope.launch {
         // TODO: Send all faults (non-periodic state) to the ApiService.
      }
   }

Perhaps instead of my requested documentation change, the suspend should be removed from the Kotlin sample in the documentation? The sample does not work for me as published.

@sdeleuze -
Thank you, Sébastien. I did not actually need to return a value, except I found that my connection always failed with suspend if I did not declare a return type.
My connection now succeeds without suspend and without a return type.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels May 22, 2020
@rstoyanchev
Copy link
Contributor

@richmeyer7 I'm sorry but I can't reproduce the issue. Please provide a sample if you'd like us to continue to look into this.

@rstoyanchev rstoyanchev added status: invalid An issue that we don't feel is valid and removed status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged or decided on labels May 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: invalid An issue that we don't feel is valid

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants