Backpressure in Spring WebFlux
Last Updated :
04 Mar, 2024
Backpressure is implemented in Spring WebFlux using the Flux and Mono API. A publisher using Flux or Mono does not send data to its subscribers when it generates it. Problems like resource contention, delay, and possible system failure might result from this imbalance.
Backpressure is a system that allows the consumer to tell the producer to slow down, which helps us deal with this imbalance. In this article, we will learn about Backpressure in Spring WebFlux.
Example of Backpressure in Spring WebFlux
Let’s go through a simple example to understand the backpressure concept.
Java
Flux.range( 1 , 100 )
.log()
.subscribe( new BaseSubscriber<Integer>() {
@Override
protected void hookOnSubscribe(Subscription subscription) {
request( 10 );
}
@Override
protected void hookOnNext(Integer value) {
System.out.println(value);
if (value % 10 == 0 ) {
request( 10 );
}
}
});
|
Control Backpressure:
- Only send out new events in response to subscriber requests. To gather elements at the emitter’s request, use this pull method. Putting a cap on how many events the client-side can get.
- When using a limited push strategy, the publisher is only able to transmit a certain number of things to the customer at once.
- When the user is unable to process any more events, the data streaming will be stopped. The receiver in this scenario has the option to stop the broadcast at any moment and rejoin the stream at a later time.
Step-by-Step Implementation of Backpressure in Spring WebFlux
Below are the steps to implement Backpressure in Spring WebFlux.
Step 1: Add Spring WebFlux starter and Reactor test dependencies
We only need to add the Reactor test dependencies and the Spring WebFlux starter to our pom.xml file in order to execute the examples:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
Step 2: Requests new events
Putting the consumer in charge of what events it can process is the first choice. The publisher therefore has to wait till the recipient requests fresh events. In conclusion, after subscribing to the Flux, the client processes the events in accordance with its demand:
Java
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
public class FluxChunkTest {
@Test
public void whenRequestingChunks10_thenMessagesAreReceived() {
Flux<Integer> fluxChunkTest = Flux.range( 15 , 20 );
StepVerifier.create(fluxChunkTest)
.expectSubscription()
.thenRequest( 10 )
.expectNext( 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 )
.thenRequest( 10 )
.expectNext( 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 )
.thenRequest( 10 )
.expectNext( 35 )
.verifyComplete();
}
}
|
- The emitter never overpowers the receiver while using this method.
- Put differently, the client is in charge of processing the events that are required of it.
- Using StepVerifier, we will test the producer’s response to backpressure.
- Only when thenRequest(n) is called can we anticipate the following n elements.
Step 3: Use the limitRange() operator
We can utilize Project Reactor’s limitRange() operator. Set how many items to prefetch at once is possible with it.
Java
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
public class LimitRateTest {
@Test
public void whenLimitRateSet_thenSplitIntoChunks() throws InterruptedException {
Flux<Integer> flux = Flux.range( 1 , 15 );
Flux<Integer> limit = flux.limitRate( 5 );
StepVerifier.create(limit)
.expectSubscription()
.thenRequest( 5 )
.expectNext( 1 , 2 , 3 , 4 , 5 )
.thenRequest( 5 )
.expectNext( 6 , 7 , 8 , 9 , 10 )
.thenRequest( 5 )
.expectNext( 11 , 12 , 13 , 14 , 15 )
.verifyComplete();
}
}
|
- The limit remains in effect even if the subscriber asks additional events to be processed, which is an intriguing feature.
- To prevent using more than the allotted amount for each request, the emitter divides the events into smaller chunks.
Step 4: Cancel the events
Lastly, the customer has the option to cancel the events at any time. We will use a different technique for this case. We can expand the BaseSubscriber or create our own Subscriber with Project Reactor.
Java
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.BaseSubscriber;
import reactor.test.StepVerifier;
public class CancelTest {
@Test
public void whenCancel_thenSubscriptionFinished() {
Flux<Integer> flux = Flux.range( 1 , 5 );
flux.subscribe( new BaseSubscriber<Integer>() {
@Override
protected void hookOnNext(Integer value) {
request( 2 );
System.out.println(value);
cancel();
}
});
StepVerifier.create(flux)
.expectNext( 1 , 2 )
.thenCancel()
.verify();
}
}
|
This is Backpressure in Spring WebFlux. Backpressure is created WebFlux using the Flux and Mono API.
Share your thoughts in the comments
Please Login to comment...