Getting Started With RSocket: Spring Boot Fire-And-Forget

Engineering | Ben Wilcock | March 16, 2020 | ...

Time: 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:

  • request/response
  • fire-and-forget
  • request/stream
  • channel

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.

Step 1: Add The Server-Side Fire-And-Forget Method

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.

Step 2: Add The Client-Side Fire-And-Forget Method

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.

Step 3: Build And Run The RSocket Server

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.

Step 4: Build And Run The RSocket Client

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)

Step 5: Tidy Up

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.

How It Works

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.

Final Thoughts

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!

Get the Spring newsletter

Stay connected with the Spring newsletter

Subscribe

Get ahead

VMware offers training and certification to turbo-charge your progress.

Learn more

Get support

Tanzu Spring offers support and binaries for OpenJDK™, Spring, and Apache Tomcat® in one simple subscription.

Learn more

Upcoming events

Check out all the upcoming events in the Spring community.

View all