Skip to content

Use @MessageMapping method signature to constrain RSocket interaction model #23999

Closed
@bclozel

Description

@bclozel

Currently, our RSocket support is mapping REQUEST_FNF, REQUEST_RESPONSE, REQUEST_STREAM and REQUEST_CHANNEL on @MessageMapping annotated handler methods on one side, SETUP and METADATA_PUSH on @ConnectMapping on the other.

Context of the issue

The case of "fire and forget" requests, where the requester sends a request and does not expect any response, can be interesting here in the context of our flexible signature support and the current mapping process.

While looking at our RSocket support with @snicoll, we considered a Controller handler that returns a response stream:

@MessageMapping("test")
public Flux<Long> test() {
	return Flux.interval(Duration.ofSeconds(1));
}

If a requester calls this handler with a fire and forget interaction type:

Mono<Void> done = requesterBuilder.dataMimeType(MediaType.APPLICATION_CBOR)
		.connectTcp("localhost", this.localPort)
		.flatMap(req -> req.route("test").send());

Then we're getting the following exception on the server side:

java.lang.IllegalArgumentException: Missing 'rsocketResponse'
	at org.springframework.util.Assert.notNull(Assert.java:198)
	at org.springframework.messaging.rsocket.annotation.support.RSocketPayloadReturnValueHandler.handleEncodedContent(RSocketPayloadReturnValueHandler.java:65)
	at org.springframework.messaging.handler.invocation.reactive.AbstractEncoderMethodReturnValueHandler.lambda$handleReturnValue$0(AbstractEncoderMethodReturnValueHandler.java:124)
	at org.springframework.messaging.handler.invocation.reactive.ChannelSendOperator$WriteBarrier.onNext(ChannelSendOperator.java:194)

In this particular case (and in general), we can find pairs of handler definitions / rsocket interactions that mismatch in our mapping infrastructure. For example, a request can be mapped to a handler, the handler is executed but the returned subscriber is not subscribed to.

After chatting with @rstoyanchev, we thought that we should enforce a few design choices in our implementation.

Refining message mappings with handler return types

First, when mapping requests on handlers, returning more elements than expected should not be allowed, but returning less than expected should be permitted.
For example:

  • a REQUEST_FNF should only be mapped on handlers that return Mono<Void> or void. Other types (even Mono<?>) should not be considered for mapping.
  • a REQUEST_RESPONSE should only be mapped on Mono types, as Flux might return more than expected. In this case, we could automatically take(1) on the returned publisher, but this goes against the general behavior we've established in reactor and webflux so far.

Not allowing ambiguous mappings

Even in the light of this (restricting message mapping depending on the handler return type), we should not allow multiple handlers with the same route. If this happens, this will be treated as an error since the mapping is ambiguous.

Metadata

Metadata

Assignees

Labels

in: messagingIssues in messaging modules (jms, messaging)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions