Get ahead
VMware offers training and certification to turbo-charge your progress.
Learn moreTime: about 15 minutes.
Some developers reading this post will have been using HTTP for many years by now. Most of them will also know that if you want to use HTTP with other messaging models — like fire-and-forget, for example — you must sometimes use clever workarounds like this one posted on Stackoverflow. That's because HTTP is a request-response protocol. It requires a request to be sent and a response to be received. It has no concept of a one-way message without any form of response.
RSocket takes a different approach. RSocket defines a new protocol layer on top of transports like TCP and WebSockets. This new protocol offers greater choice to developers, with built-in support for four distinct interaction models:
In the previous posts, you already learned how to do request-response with RSocket. In this post, you're going to learn how to add fire-and-forget messaging to your code. Let's dive right in!
If you didn't read the previous posts on server-side and client-side request-response messaging with RSocket, now's your chance! The code sample is on GitHub.
You'll remember the RSocketController
from the rsocket-server
project that you worked on earlier:
@Slf4j
@Controller
public class RSocketController {
// code goes here
}
The RSocketController
is the server-side class that dealt with request-response messaging. Its .requestResponse()
method accepted a Message
object as a parameter and returned a Message
object as a response. It's this one-object-in, one-object-out method signature that makes the method a request-response method.
To add a fire-and-forget capability to the server, you must add a method with a different signature. The .fireAndForget()
method should accept a single Message
parameter, but this time, return a void
like this...
@MessageMapping("fire-and-forget")
public void fireAndForget(Message request) {
log.info("Received fire-and-forget request: {}", request);
}
You must still use the @MessageMapping
annotation on your method, but this time you must give the route mapping a different name. In the code above, I've used the name "fire-and-forget."
In the Spring RSocket documentation, the method signature rules are in the message mapping section.
You built your RSocketShellClient
in the rsocket-client
project when you followed the previous post:
@Slf4j
@ShellComponent
public class RSocketShellClient {
// code goes here
}
RSocketShellClient used the .requestResponse()
method to send a single request to the RSocket server using the RSocketRequester
created in the class constructor.
To add the fire-and-forget capability to your client, add a new .fireAndForget()
method to the RSocketShellClient
like this:
@ShellMethod("Send one request. No response will be returned.")
public void fireAndForget() throws InterruptedException {
log.info("\nFire-And-Forget. Sending one request. Expect no response (check server log)...");
this.rsocketRequester
.route("fire-and-forget")
.data(new Message(CLIENT, FIRE_AND_FORGET))
.send()
.block();
}
Let's examine the code in this method in more detail:
The .route()
on the rsocketRequester
is set to "fire-and-forget"
. This route name matches the @MessageMapping
annotation on the fire-and-forget method in the RSocketController.
A new Message
instance provides the data for the .data()
method. The message instance has its origin set to CLIENT
and FIRE_AND_FORGET
set as its interaction mode.
Notice that there is no .retrieveMono()
call. Instead, the fire-and-forget specific .send()
method sends the message to the server, while .block()
subscribes and waits for completion. Remember, nothing happens in reactive code without a subscription.
That's all the coding done. Now, it's time to test it's working.
Open a terminal window and move to the rsocket-server
directory. Start running the server using the Maven wrapper like this:
cd rsocket-server
./mvnw clean package spring-boot:run -DskipTests=true
The server starts on localhost
port 7000
.
For details on how to run a Linux terminal on Windows 10, see this quick guide from Ubuntu.
Open a second terminal window and move to the rsocket-client
directory. From there, build and run the client application as follows:
cd rsocket-client
./mvnw clean package spring-boot:run -DskipTests=true
When the client runs, Spring Shell presents you with a new prompt:
shell:>
You can send your fire-and-forget message to the server by typing fire-and-forget
at the prompt.
shell:>fire-and-forget
2020-02-03 14:54:14.028 INFO 2929 --- [ main] io.pivotal.rsocketclient.RSocketClient :
Fire-And-Forget. Sending one request. Expect no response (check server)...
The client prints no response, but if you switch to the server's terminal window, you'll notice the receipt of the fire-and-forget message is logged successfully to the console:
2020-02-03 14:54:14.129 INFO 2061 --- [or-http-epoll-2] io.pivotal.rsocketserver.RSocketServer : Received fire-and-forget request: Message(origin=Client, interaction=Fire-And-Forget, index=0, created=1580741654)
You can stop the rsocket-client
by typing exit at the shell:>
prompt like this.
shell:>exit
You can stop the rsocket-server
process by pressing Ctrl-C
in its terminal window.
The client's .fireAndForget()
method uses the RSocketRequester
to send a single Message
to the server when the block()
method is called. The block method is effectively an instruction to 'subscribe and wait.'
The RSocketController
on the server examines the message metadata for the route
and correctly passes the message to the .fireAndForget(Message request)
method for processing. Once the client sends the request, it is free to get on with other things. When the server receives the request, it too can get on with other work. It does not need to send a response to the client.
In this post, you learned how to quickly build a fire and forget capability with Spring Boot and RSocket. For more on Spring's RSocket integration and message mapping, take a look at the Spring RSocket documentation. In the next post, we'll cover request-stream messaging. See you there!