0% found this document useful (0 votes)
2 views62 pages

Reactive Notes

A Reactive System is an architectural approach that emphasizes responsiveness, resilience, scalability, and efficient handling of data and user requests, as defined by the Reactive Manifesto. Reactive Programming is a paradigm focused on asynchronous data streams and event-driven processing, allowing applications to react to data as it arrives rather than blocking for operations to complete. The document also covers the components of Reactive Streams, including Publisher, Subscriber, Subscription, and Processor, and introduces Project Reactor, a library for building non-blocking applications.

Uploaded by

Birendra Singh
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views62 pages

Reactive Notes

A Reactive System is an architectural approach that emphasizes responsiveness, resilience, scalability, and efficient handling of data and user requests, as defined by the Reactive Manifesto. Reactive Programming is a paradigm focused on asynchronous data streams and event-driven processing, allowing applications to react to data as it arrives rather than blocking for operations to complete. The document also covers the components of Reactive Streams, including Publisher, Subscriber, Subscription, and Processor, and introduces Project Reactor, a library for building non-blocking applications.

Uploaded by

Birendra Singh
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

1. What is a Reactive System?

A Reactive System is an architectural approach for building applications


that are highly responsive, resilient, scalable, and capable of handling large
volumes of data and user requests efficiently.

The concept is defined by the Reactive Manifesto, which describes the key
characteristics of reactive applications.

[Link]

Definition
A Reactive System is a system that:

 Responds quickly to user requests.

 Remains available even when failures occur.

 Scales up or down automatically based on workload.

 Handles asynchronous communication efficiently.

Core Characteristics of Reactive Systems


1. Responsive
A reactive system should always provide a timely response.

Key Points
 Users should receive quick responses to requests.

 The system should maintain consistent response times under varying


workloads.

 Fast responses improve user experience.

 Responsiveness helps identify problems quickly.

Example
 An online banking application should display account balances within
seconds, even during peak usage hours.

2. Resilient
A reactive system should remain operational even when failures occur.

Key Points
 Failures should be isolated.

 One component failure should not crash the entire application.

 Recovery should happen automatically.

 Fault tolerance is built into the system.

Example
 If a payment service fails, the order service should continue
functioning and retry the payment later.

3. Elastic
A reactive system should scale according to demand.

Key Points
 Resources can be added automatically during high traffic.

 Resources can be reduced during low traffic.

 Supports horizontal scaling.

 Maintains performance during workload spikes.

Example
 During a festival sale, an e-commerce application automatically
increases server instances to handle additional users.

4. Message-Driven
Reactive systems communicate using asynchronous messages.

Key Points
 Components are loosely coupled.

 Services communicate without blocking each other.

 Messages can be processed independently.

 Supports distributed architectures.

Example
 Order Service sends a message to Inventory Service through a
message broker like Apache Kafka without waiting for an immediate
response.
Benefits of Reactive Systems
Improved User Experience
 Faster responses.

 Better availability.

 Reduced downtime.

Better Scalability
 Can handle millions of requests.

 Supports cloud-native architectures.

 Efficient resource utilization.

Enhanced Reliability
 Failure isolation.

 Automatic recovery mechanisms.

 High availability.

Efficient Resource Utilization


 Less CPU wastage.

 Better memory utilization.

 Reduced infrastructure costs.

2. What is Reactive Programming?


Definition
Reactive Programming is a programming paradigm that focuses on handling
asynchronous data streams and event-driven processing.

Instead of waiting for operations to complete, applications react to data as it


arrives.

Traditional Programming vs Reactive Programming


Traditional (Blocking)
Request -> Processing -> Wait -> Response
Reactive (Non-Blocking)
Request -> Continue Processing
|
Data Arrives
|
React & Respond

Key Concepts of Reactive Programming


1. Asynchronous Processing
Tasks execute independently without blocking threads.

Characteristics
 No waiting for I/O operations.

 Better throughput.

 More efficient thread usage.

2. Non-Blocking Execution
Threads are not blocked while waiting for results.

3. Event-Driven Architecture
Applications react to events.

Examples of Events
 User clicks a button.

 New order is created.

 Payment completed.

 Sensor sends data.

4. Data Streams
Reactive programming treats data as streams. Instead of processing one
value at a time, the application continuously reacts to incoming values.

5. Backpressure
Backpressure prevents consumers from being overwhelmed by data
producers.
Problem
Producer -> 10000 events/sec
Consumer -> 100 events/sec

Consumer crashes due to overload.

Solution
Consumer requests data at its own pace.

Producer ---> Consumer


Request(100)

Thread per request model vs Event Loop


[Link]
mod

1. Thread-per-Request Model (Traditional Servlet Model)


This model is used by:

 Spring MVC

 Java Servlets

 Tomcat (Traditional Mode)

 JAX-RS

 Most synchronous web frameworks

How It Works
When a request arrives:

1. Server receives the request.

2. A thread is allocated from the thread pool.

3. The thread processes the entire request.

4. The thread waits for database calls, API calls, file operations, etc.

5. After sending the response, the thread is released back to the pool.

Flow
Request 1 --> Thread 1
Request 2 --> Thread 2
Request 3 --> Thread 3
Request 4 --> Thread 4

Every request gets its own dedicated thread.

2. Event Loop Model (Reactive Systems)


Used by:

 Spring WebFlux

 Project Reactor

 Netty

 [Link]

 Vert.x

The Event Loop Model uses a small number of threads to handle thousands
of requests.

How It Works
Instead of assigning one thread per request:

1. Request arrives.

2. Event Loop receives the request.

3. Non-blocking operation starts.

4. Event Loop immediately moves to another request.

5. When operation completes, callback is executed.


Flow
Request 1
Request 2
Request 3
Request 4

Single Event Loop

One thread can manage many requests.

Why Reactive Programming is Needed


1. To Handle High Concurrency Efficiently
 Traditional applications use a thread-per-request model.

 When thousands of users access the application simultaneously,


thousands of threads may be required.

 Creating and managing a large number of threads consumes


significant memory and CPU resources.

 Reactive Programming uses a small number of threads and handles


multiple requests asynchronously, improving scalability.
2. To Improve Resource Utilization
 In traditional programming, a thread remains blocked while waiting for:

o Database responses

o External API calls

o File operations

o Network communication

 During this waiting period, system resources are wasted.

 Reactive Programming allows threads to perform other tasks instead of


waiting, resulting in better resource utilization.

3. To Build Responsive Applications


 Modern applications require quick response times even under heavy
load.

 Reactive systems process events asynchronously and respond faster.

 Users experience lower latency and better performance.

4. To Support Real-Time Data Processing


 Many modern applications continuously process incoming data
streams.

 Examples include:

o Stock market systems

o Social media feeds

o IoT sensor data

o Chat applications

o Live notifications

 Reactive Programming is well-suited for handling continuous streams


of data.

5. To Improve Scalability
 Applications must scale as user traffic increases.
 Reactive applications can handle more requests with fewer hardware
resources.

 This makes them suitable for cloud-native and distributed


environments.

6. To Support Event-Driven Architectures


 Modern systems are increasingly event-driven.

 Events such as user actions, messages, and system notifications


trigger processing.

 Reactive Programming naturally fits event-driven architectures by


reacting to incoming events.

7. To Build Microservices Efficiently


 Microservices often communicate with multiple external services.

 Synchronous communication can cause thread blocking.

 Reactive Programming enables non-blocking communication between


services, improving overall system throughput.

8. To Handle Streaming Data


 Data may arrive continuously over time rather than all at once.

 Reactive streams provide mechanisms to process data incrementally.

 Applications can react to data as soon as it arrives.

9. To Support Backpressure
 Producers may generate data faster than consumers can process it.

 This can lead to memory issues and system crashes.

 Reactive Programming introduces backpressure, allowing consumers


to control the rate of data consumption.

10. To Build Resilient Systems


 Reactive systems can recover from failures more effectively.

 They support:

o Error handling

o Retry mechanisms
o Timeout management

o Fallback strategies

 This improves application reliability.

Reactive Streams Specification and Project


Reactor
1. What is Reactive Streams?
Reactive Streams is a specification (standard) for building asynchronous,
non-blocking, and backpressure-aware applications.

It defines a standard for communication between components that produce


data and components that consume data.

Goals of Reactive Streams


 Asynchronous processing of data streams.

 Non-blocking communication between components.

 Efficient resource utilization.

 Support for handling large volumes of data.

 Provide Backpressure mechanism to avoid overwhelming consumers.

 Enable interoperability between different reactive libraries.

Problem Solved by Reactive Streams


In traditional systems:

 Producer generates data rapidly.

 Consumer processes data slowly.

 Producer continues sending data.

 Memory consumption increases.

 System may crash due to OutOfMemoryError.

Reactive Streams introduces Backpressure so consumers can control how


much data they receive.
What is Project Reactor?
Project Reactor is a Reactive Programming library developed by VMware and
now widely used in the Spring ecosystem.

It is the foundation of Spring WebFlux and implements the Reactive Streams


specification.

Features of Project Reactor


 Reactive Streams compliant.

 Non-blocking programming model.

 Backpressure support.

 Functional programming style.

 High throughput.

 Event-driven architecture.

 Asynchronous processing.

 Rich operators for data transformation.

Reactive Streams Components


Reactive Streams is a standard specification for asynchronous, non-blocking,
and backpressure-aware data processing. It defines four core components:

1. Publisher

2. Subscriber

3. Subscription

4. Processor

These components work together to enable controlled data flow between


producers and consumers.

1. Publisher
Definition
A Publisher is a data producer that generates and emits data items to one
or more subscribers.
It is the starting point of a reactive stream.

public interface Publisher<T> {


void subscribe(Subscriber<? super T> subscriber);
}

Responsibilities of Publisher
 Produces data items.

 Maintains a list of subscribers.

 Sends data only when requested by subscribers.

 Handles backpressure.

 Sends completion notifications.

 Sends error notifications.

 Stops sending data after completion or error.

Key Characteristics
 Can have multiple subscribers.

 Does not push unlimited data.

 Waits for demand from subscribers.

 Supports asynchronous data generation.

 Supports non-blocking communication.

Examples
Reactor

Flux<Integer> numbers =
[Link](1, 10);

Real-World Analogy
Consider a newspaper company:

 Newspaper company = Publisher

 Newspapers = Data

 Subscribers = Readers

The publisher distributes newspapers only to registered subscribers.


2. Subscriber
Definition
A Subscriber is a consumer that receives and processes data emitted by a
publisher.

public interface Subscriber<T> {

void onSubscribe(Subscription subscription);

void onNext(T item);

void onError(Throwable throwable);

void onComplete();
}

Responsibilities of Subscriber
 Subscribes to a publisher.

 Requests data.

 Processes received data.

 Handles errors.

 Handles completion events.

 Controls data flow using backpressure.

Subscriber Lifecycle Methods


1. onSubscribe()
Called once when subscription is established.

public void onSubscribe(


Subscription subscription)

Purpose:

 Receive Subscription object.

 Request required number of items.


Example:
[Link](5);

2. onNext()
Called whenever a new item arrives.

public void onNext(T item)

Example:
public void onNext(Integer value) {
[Link](value);
}

3. onError()
Called when an error occurs.

public void onError(Throwable error)

Example:
public void onError(Throwable error) {
[Link]([Link]());
}

4. onComplete()
Called when all data has been successfully delivered.

public void onComplete()

Real-World Analogy
Food Delivery System:

 Restaurant = Publisher

 Customer = Subscriber

 Food Items = Data

Customer receives food items and decides how much to order.

3. Subscription
Definition
A Subscription represents the connection between a Publisher and a
Subscriber.
It is responsible for demand management and cancellation.

public interface Subscription {

void request(long n);

void cancel();
}

Responsibilities of Subscription
 Establishes communication channel.

 Controls data flow.

 Supports backpressure.

 Allows subscriber to request data.

 Allows subscriber to cancel stream.

request(long n)
Requests a specific number of items from publisher.
[Link](10);
cancel()
Terminates subscription.

[Link]();

Why Subscription Is Important


Without Subscription:

Publisher → Unlimited Data


Subscriber → Slow Processing
Result → Memory Overflow

With Subscription:

Subscriber requests data


Publisher sends only requested data

This enables backpressure.

Real-World Analogy
Online Shopping:

 Customer places order.


 Order acts like Subscription.

 Customer can:

o Request more products.

o Cancel order.

4. Processor
Definition
A Processor acts as both:

 Subscriber

 Publisher

public interface Processor<T,R>


extends Subscriber<T>,
Publisher<R> {
}

Responsibilities of Processor
 Receives data from upstream publisher.

 Processes or transforms data.

 Publishes transformed data downstream.

 Can filter data.

 Can aggregate data.

 Can enrich data.

Data Flow
Publisher
|
v
Processor
|
v
Subscriber
Interaction Between Components
Step-by-Step Flow
Step 1: Subscriber subscribes to Publisher.
[Link](subscriber);

Step 2: Publisher invokes:


[Link](subscription);

Step 3: Subscriber requests data.


[Link](5);

Step 4: Publisher sends requested items.


[Link](item);

Step 5: Publisher either:Completes or Sends Error


[Link]();

[Link](error);

Project Reactor Modules


Project Reactor is a reactive programming library for building non-blocking,
asynchronous applications on the JVM. It is the foundation of reactive support
in Spring WebFlux and Spring Reactive Stack.

1. reactor-core
reactor-core is the primary module of Project Reactor.

Purpose

 Provides the Reactive Streams implementation.

 Contains the core reactive types:

o Mono<T> → Represents 0 or 1 item.

o Flux<T> → Represents 0 to N items.

 Supports asynchronous and non-blocking data processing.

Key Features
 Reactive Streams compliant.

 Backpressure support.
 Functional programming style APIs.

 Rich set of operators for data transformation and manipulation.

 Error handling mechanisms.

 Thread management through Schedulers.

Common Operators
Creation Operators
o just()

o fromIterable()

o empty()

o error()

o range()

Transformation Operators
o map()

o flatMap()

o concatMap()

Filtering Operators
o filter()

o take()

o skip()

Combination Operators
o merge()

o concat()

o zip()

2. reactor-test
reactor-test provides utilities for testing reactive applications.

Purpose
 Testing Flux and Mono sequences.

 Verifying emitted data.


 Verifying completion signals.

 Testing error scenarios.

 Testing time-based operations.

Key Components
StepVerifier
Most commonly used testing utility.

Used for:

 Validating emitted items.

 Verifying completion.

 Verifying errors.

3. reactor-netty
reactor-netty is a reactive networking library built on top of the Netty
framework.

Purpose
 Provides non-blocking HTTP/TCP/UDP clients and servers.

 Used internally by Spring WebFlux.

 Supports high-throughput and event-driven networking.

Key Features
 Event Loop Architecture.

 Non-blocking I/O.

 High scalability.

 HTTP/1.1 support.

 HTTP/2 support.

 WebSocket support.

 TCP/UDP communication.
Reactor Core Types
Project Reactor provides two primary reactive types in the reactor-core
module:

1. Mono<T>

2. Flux<T>

These types implement the Reactive Streams Publisher interface and form
the foundation of reactive programming in Project Reactor and Spring
WebFlux.

1. Mono<T>
Definition
 Mono<T> is a Publisher that emits:

o Zero elements and completes, or

o One element and completes, or

o An error signal

 It is used when the result contains at most one value.

Characteristics
 Represents an asynchronous computation producing a single result.

 Similar to:

o Optional<T> (for synchronous programming)

o Future<T> or CompletableFuture<T> (for asynchronous


programming)

 Supports non-blocking execution.

 Emits only one item at most.

Mono Signal Flow


Mono

├── onNext(item)

└── onComplete()
Or

Mono

└── onError(exception)

Common Use Cases


 Fetching a customer by ID.

 Retrieving a single database record.

 Login authentication result.

 Calling an external service returning one response.

 Reading a configuration value.

2. Flux<T>
Definition
 Flux<T> is a Publisher that emits:

o Zero items

o One item

o Multiple items

o Infinite items

o Error signal

Characteristics
 Represents a stream of data.

 Can emit any number of elements.

 Supports asynchronous data processing.

 Most commonly used type in reactive applications

Flux Signal Flow


Flux

├── onNext(item1)
├── onNext(item2)
├── onNext(item3)

└── onComplete()
Or
Flux

└── onError(exception)

Common Use Cases


 Retrieving all customers.

 Streaming database records.

 Processing events.

 Reading file contents.

 Sensor data streaming.

 Real-time stock prices.

 Chat applications.

Mono Methods in Project Reactor


1. Creation Methods
These methods create a Mono instance.

[Link]()
Purpose
 Creates a Mono that emits a specified value.

 Value must not be null.

Syntax
Mono<String> mono = [Link]("Spring");

Characteristics
 Immediately emits the value.

 Completes after emitting the value.

 Most commonly used creation method.

Example
[Link]("Java")
.subscribe([Link]::println);
[Link]()
Purpose
 Creates a Mono from a nullable value.

 Emits the value if present.

 Completes empty if null.

Example
String name = null;

Mono<String> mono = [Link](name);

Benefits
 Eliminates null checks.

 Useful with Optional values.

[Link]()
Purpose
 Creates a Mono that emits no value.

 Only sends completion signal.

Example
Mono<String> mono = [Link]();

Signal Flow
onComplete()

Use Cases
 No data found.

 Optional results.

 Empty responses.

[Link]()
Purpose
 Creates a Mono that immediately emits an error.

Example
Mono<String> mono =
[Link](
new RuntimeException("Error"));
Signal Flow
onError()

Use Cases
 Validation failure.

 Business exceptions.

 Custom error handling

[Link]()
Purpose
 Creates a Mono from a Callable.

 Executes lazily upon subscription.

Example
Mono<String> mono =
[Link](() ->
"Generated Value");

Benefits
 Deferred execution.

 Exception handling support.

[Link]()
Purpose
 Creates Mono from a Supplier.

Example
Mono<String> mono =
[Link](() ->
"Dynamic Value");

Characteristics
 Executes only when subscribed.

 Suitable for lightweight operations.

[Link]()
Purpose
 Delays Mono creation until subscription time.
Example
Mono<String> mono =
[Link](() ->
[Link](getData()));

Benefits
 Fresh data for each subscription.

 Lazy initialization.

[Link]()
Purpose
 Delays Mono creation until subscription time.

Example
Mono<String> mono =
[Link](() ->
[Link](getData()));

Benefits
 Fresh data for each subscription.

 Lazy initialization.

map()
Purpose
 Converts one value into another value.

 Synchronous transformation.

Example
[Link]("java")
.map(String::toUpperCase);

Characteristics
 Returns Mono<R>.

 Executes synchronously.

flatMap()
Purpose
 Converts value into another Mono.
Example
[Link]("java")
.flatMap(value ->
[Link]([Link]()));

Characteristics
 Used when transformation returns Mono.

 Avoids nested Monos.

cast()
Purpose
 Converts object type.

Example
Mono<Object> mono =
[Link]("Spring");

[Link]([Link]);

3. Filtering Methods
Used to decide whether a value should continue.

filter()
Purpose
 Passes value only if condition is true.

Example
[Link]("Spring")
.filter(name ->
[Link]() > 5);

filterWhen()
Purpose
 Performs asynchronous filtering.

Example
[Link]("Spring")
.filterWhen(
value ->
[Link]([Link]() > 5));
Benefits
 Reactive condition evaluation.

 Database-based validation.

4. Default and Fallback Methods


Used when Mono is empty.

defaultIfEmpty()
Purpose
 Provides default value.

Example
[Link]()
.defaultIfEmpty("Default");

switchIfEmpty()
Purpose
 Switches to another Mono.

Example
[Link]()
.switchIfEmpty(
[Link]("Fallback"));

Use Cases
 Cache fallback.

 Database fallback.

 Alternative service calls.

5. Error Handling Methods


Used for exception management.

onErrorReturn()
Purpose
 Returns fallback value.

Example
[Link](new RuntimeException())
.onErrorReturn("Default");
onErrorResume()
Purpose
 Switches to another Mono when error occurs.

Example
[Link](new RuntimeException())
.onErrorResume(
ex -> [Link]("Recovered"));

Use Cases
 Service fallback.

 Cache lookup.

 Alternative API call.

onErrorMap()
Purpose
 Converts one exception into another.

Example
[Link](new RuntimeException())
.onErrorMap(
ex ->
new IllegalArgumentException());

doOnError()
Purpose
 Executes side-effect logic.

Example
[Link](new RuntimeException())
.doOnError(
error ->
[Link]([Link]()));

Use Cases
 Logging.

 Monitoring.

 Metrics collection.
6. Side Effect Methods
Used for logging and monitoring.

doOnNext()
Purpose
 Executes action when value is emitted.

Example
[Link]("Spring")
.doOnNext([Link]::println);

doOnSuccess()
Purpose
 Executes action after successful completion.

Example
[Link]("Java")
.doOnSuccess(
value ->
[Link]("Success"));

doOnSubscribe()
Purpose
 Executes when subscription occurs.

Example
[Link]("Java")
.doOnSubscribe(
sub ->
[Link]("Subscribed"));

doOnTerminate()
Purpose
 Executes on completion or error.

Example
[Link]("Java")
.doOnTerminate(
() -> [Link]("Done"));
7. Combining Methods
Used to combine Monos.

zip()
Purpose
 Combines multiple Monos.

Example
Mono<String> first =
[Link]("Java");

Mono<String> second =
[Link]("Spring");

[Link](first, second);

then()
Purpose
 Ignores current value.

 Executes next Mono.

Example
[Link]("A")
.then([Link]("B"));

thenReturn()
Purpose
 Returns specified value after completion.

Example
[Link]("Java")
.thenReturn("Completed");

8. Scheduling Methods
Used for thread management.

subscribeOn()
Purpose
 Controls source execution thread.
Example
[Link]("Spring")
.subscribeOn(
[Link]());

Typical Uses
 Database calls.

 File operations.

 Blocking APIs.

publishOn()
Purpose
 Changes downstream execution thread.

Example
[Link]("Spring")
.publishOn(
[Link]());

Typical Uses
 CPU-intensive tasks.

 Data transformation.

9. Blocking Methods
Used mainly for testing and legacy integration.

block()
Purpose
 Waits for Mono result synchronously.

Example
String result =
[Link]("Spring")
.block();

blockOptional()
Purpose
 Returns Optional result.
Example
Optional<String> result =
[Link]("Java")
.blockOptional();

10. Subscription Methods


Used to start execution.

subscribe()
Purpose
 Triggers Mono execution.

Example
[Link]("Spring")
.subscribe();

subscribe(Consumer)
Example
[Link]("Java")
.subscribe(
[Link]::println);

subscribe(Value, Error)
Example
[Link]("Java")
.subscribe(
[Link]::println,
Throwable::printStackTrace);

Flux Methods in Project Reactor


1. Creation Methods
These methods create a Flux instance.

[Link]()
Purpose
 Creates a Flux with one or more predefined values.

 Emits values sequentially and then completes.


Example
Flux<String> flux =
[Link]("Java", "Spring", "Reactor");

Use Cases
 Static data.

 Sample datasets.

 Testing.

[Link]()
Purpose
 Creates a Flux from a Collection.

Example
List<String> names =
[Link]("John", "David", "Scott");

Flux<String> flux =
[Link](names);

Use Cases
 Lists.

 Sets.

 Database results.

[Link]()
Purpose
 Creates a Flux from an array.

Example
String[] names =
{"Java", "Spring", "Reactor"};

Flux<String> flux =
[Link](names);

[Link]()
Purpose
 Generates a sequence of integers.
Example
Flux<Integer> flux =
[Link](1, 5);

[Link]()
Purpose
 Generates values at fixed intervals.

 Creates an infinite stream.

Example
Flux<Long> flux =
[Link]([Link](1));

Use Cases
 Event streaming.

 Polling services.

 Real-time monitoring.

[Link]()
Purpose
 Creates an empty Flux.

Example
Flux<String> flux =
[Link]();

[Link]()
Purpose
 Creates a Flux that immediately emits an error.

Example
Flux<String> flux =
[Link](
new RuntimeException("Error"));

[Link]()
Purpose
 Creates Flux lazily.

 New Flux instance for each subscriber.


Example
Flux<String> flux =
[Link](() ->
[Link](getData()));

2. Transformation Methods
Used to transform emitted values.

map()
Purpose
 Converts each element into another element.

 One input → One output.

Example
[Link]("java", "spring")
.map(String::toUpperCase);

flatMap()
Purpose
 Converts each element into another Publisher.

 Flattens results.

Example
[Link]("java", "spring")
.flatMap(
value ->
[Link]([Link]()));

Characteristics
 Asynchronous.

 Order not guaranteed.

concatMap()
Purpose
 Similar to flatMap().

 Preserves order.
Example
[Link]("A", "B", "C")
.concatMap(
value -> [Link](value));

Use Cases
 Ordered processing.

 Sequential execution.

flatMapSequential()
Purpose
 Executes concurrently.

 Preserves original order.

Benefits
 Better performance than concatMap.

 Ordered results.

3. Filtering Methods
Used to select required elements.

filter()
Purpose
 Emits only matching elements.

Example
[Link](1,10)
.filter(i -> i % 2 == 0);

filterWhen()
Purpose
 Performs asynchronous filtering.

Example
[Link]("Java","Spring")
.filterWhen(
value ->
[Link]([Link]() > 4));
distinct()
Purpose
 Removes duplicate elements.

Example
[Link](1,2,2,3,3,4)
.distinct();

take()
Purpose
 Takes first N elements.

Example
[Link](1,100)
.take(5);

skip()
Purpose
 Skips first N elements.

Example
[Link](1,10)
.skip(5);

4. Aggregation Methods
Used to collect data.

collectList()
Purpose
 Converts Flux into Mono<List<T>>.

Example
[Link]("A","B","C")
.collectList();

collectMap()
Purpose
 Converts Flux into Map.
Example
[Link]("Java","Spring")
.collectMap(
value -> [Link]());

count()
Purpose
 Counts emitted elements.

Example
[Link](1,10)
.count();

reduce()
Purpose
 Combines all elements into one result.

Example
[Link](1,5)
.reduce((a,b) -> a+b);

5. Combining Methods
Used to combine multiple publishers.

concat()
Purpose
 Sequentially combines publishers.

Example
[Link](
[Link]("A","B"),
[Link]("C","D"));

merge()
Purpose
 Combines publishers concurrently.

Example
[Link](flux1, flux2);
Characteristics
 Faster.

 Order not guaranteed.

zip()
Purpose
 Combines corresponding elements.

Example
[Link](
[Link]("A","B"),
[Link](1,2));

combineLatest()
Purpose
 Combines latest emitted values.

Use Cases
 Dashboards.

 Real-time applications.

 Live monitoring.

6. Error Handling Methods


Used for exception management.

onErrorReturn()
Purpose
 Returns default value on error.
Example
[Link](new RuntimeException())
.onErrorReturn("Default");

onErrorResume()
Purpose
 Switches to fallback Flux.

Example
[Link](new RuntimeException())
.onErrorResume(
error ->
[Link]("Fallback"));

onErrorMap()
Purpose
 Converts one exception into another.

Example
[Link](new RuntimeException())
.onErrorMap(
error ->
new IllegalArgumentException());

retry()
Purpose
 Retries execution.

Example
[Link](new RuntimeException())
.retry(3);

Use Cases
 Network failures.

 Temporary service outages.

7. Side Effect Methods


Used for logging and monitoring.

doOnNext()
Purpose
 Executes action for each emitted item.
Example
[Link]("A","B")
.doOnNext([Link]::println);

doOnSubscribe()
Purpose
 Executes when subscription starts.
Example
[Link]("Java")
.doOnSubscribe(
s ->
[Link]("Subscribed"));

doOnComplete()
Purpose
 Executes when stream completes.
Example
[Link]("A","B")
.doOnComplete(
() -> [Link]("Done"));

doOnError()
Purpose
 Executes when error occurs.
Example
[Link](new RuntimeException())
.doOnError(
Throwable::printStackTrace);

doFinally()
Purpose
 Executes regardless of outcome.
Example
[Link]("A")
.doFinally(
signal ->
[Link]("Finished"));

8. Scheduling Methods
Used for thread management.

subscribeOn()
Purpose
 Determines thread for source execution.
Example
[Link](1,10)
.subscribeOn(
[Link]());

publishOn()
Purpose
 Changes downstream execution thread.
Example
[Link](1,10)
.publishOn(
[Link]());

9. Backpressure Methods
Used to control data flow.

limitRate()
Purpose
 Limits requested items.
Example
[Link](1,1000)
.limitRate(10);

onBackpressureBuffer()
Purpose
 Buffers excess items.
Example
[Link]([Link](1))
.onBackpressureBuffer();

onBackpressureDrop()
Purpose
 Drops excess items.
Example
[Link]([Link](1))
.onBackpressureDrop();
10. Subscription Methods
Used to start processing.

subscribe()
Purpose
 Triggers execution.
Example
[Link]("Java")
.subscribe();

subscribe(Consumer)
Example
[Link]("Java","Spring")
.subscribe([Link]::println);

subscribe(Value, Error)
Example
[Link]("Java")
.subscribe(
[Link]::println,
Throwable::printStackTrace);

StepVerifier in Project Reactor


What is StepVerifier?
 StepVerifier is a testing utility provided by the reactor-test module.
 It is used to test and verify the behavior of reactive streams (Mono and Flux).
 It subscribes to a Publisher and verifies emitted signals step-by-step.
 It helps validate:
o Emitted data (onNext)

o Stream completion (onComplete)

o Errors (onError)

o Cancellation

o Backpressure
o Time-based operations

 It is the most commonly used testing tool for Reactor applications and Spring WebFlux
applications.

Why StepVerifier is Required?


Without StepVerifier:
Flux<String> flux = [Link]("Java", "Spring");

[Link]([Link]::println);
Problems
 No automated verification.
 Cannot validate expected values.
 Cannot validate completion signals.
 Cannot validate errors.
 Not suitable for unit testing.
With StepVerifier:
[Link](flux)
.expectNext("Java")
.expectNext("Spring")
.verifyComplete();
Benefits
 Automated assertions.
 Repeatable tests.
 Easy validation of reactive streams.
 Better readability.

Basic Workflow of StepVerifier


Publisher


[Link]()


Expect Signals


Verify Results

Core Methods of StepVerifier


1. create()
Purpose
 Creates a StepVerifier instance for a Publisher.
Syntax
[Link](publisher)
Example
Flux<String> flux =
[Link]("Java", "Spring");

[Link](flux);

2. expectNext()
Purpose
 Verifies the next emitted element.
Example
Flux<String> flux =
[Link]("Java", "Spring");

[Link](flux)
.expectNext("Java")
.expectNext("Spring")
.verifyComplete();

3. expectNextCount()
Purpose
 Verifies the number of emitted items.
 Does not verify actual values.
Example
Flux<Integer> flux =
[Link](1, 5);
[Link](flux)
.expectNextCount(5)
.verifyComplete();
Use Cases
 Large datasets.
 Performance testing.
 Stream size verification.

4. expectNextMatches()
Purpose
 Validates emitted values using a Predicate.
Example
[Link](
[Link]("Java"))
.expectNextMatches(
value -> [Link]("J"))
.verifyComplete();
Benefits
 Flexible validation.
 Complex assertions.

5. assertNext()
Purpose
 Allows detailed assertions on emitted values.
Example
[Link](
[Link]("Spring"))
.assertNext(value -> {
assert [Link]("Spring");
})
.verifyComplete();
Use Cases
 Multiple field validations.
 Object property verification.
6. verifyComplete()
Purpose
 Verifies stream completes successfully.
Example
[Link](
[Link]("A", "B"))
.expectNext("A")
.expectNext("B")
.verifyComplete();

7. expectComplete()
Purpose
 Expects completion signal.
Example
[Link](
[Link]("A"))
.expectNext("A")
.expectComplete()
.verify();

Error Verification Methods


8. expectError()
Purpose
 Verifies that an error occurs.
Example
[Link](
[Link](
new RuntimeException()))
.expectError()
.verify();

9. expectError(Class)
Purpose
 Verifies specific exception type.
Example
[Link](
[Link](
new IllegalArgumentException()))
.expectError(
[Link])
.verify();

10. expectErrorMessage()
Purpose
 Verifies error message.
Example
[Link](
[Link](
new RuntimeException("Failed")))
.expectErrorMessage("Failed")
.verify();

11. expectErrorMatches()
Purpose
 Validates exception using Predicate.
Example
[Link](
[Link](
new RuntimeException("Failed")))
.expectErrorMatches(
ex -> [Link]()
.contains("Fail"))
.verify();

Verification Methods
12. verify()
Purpose
 Executes verification.
Example
[Link](
[Link]("Java"))
.expectNext("Java")
.verify();
Characteristics
 Triggers subscription.
 Starts verification process.

13. verify(Duration)
Purpose
 Sets maximum verification time.
Example
[Link](
[Link]("Java"))
.expectNext("Java")
.verify([Link](5));
Benefits
 Prevents hanging tests.
 Controls execution time.

Time-Based Testing
Why Virtual Time?
Suppose a Flux emits data every 1 minute.
[Link]([Link](1))
Testing would take real time. This slows down testing.

14. withVirtualTime()
Purpose
 Simulates time.
 Avoids actual waiting.
Example
[Link](
() -> [Link](
[Link](5))
.take(3))
.thenAwait([Link](15))
.expectNext(0L,1L,2L)
.verifyComplete();
Benefits
 Faster tests.
 No [Link]().
 Efficient testing.

15. thenAwait()
Purpose
 Advances virtual time.
Example
.thenAwait([Link](10))
Use Cases
 Delayed streams.
 Scheduled tasks.
 Retry operations.

Backpressure Testing
16. thenRequest()
Purpose
 Requests additional items.
Example
[Link](
[Link](1,10), 2)
.expectNext(1,2)
.thenRequest(3)
.expectNext(3,4,5)
.thenCancel()
.verify();
Cancellation Testing
17. thenCancel()
Purpose
 Cancels subscription.
Example
[Link](
[Link](
[Link](1)))
.expectNext(0L)
.thenCancel()
.verify();
Use Cases
 Infinite streams.
 Resource cleanup testing.

What is Backpressure in Reactive


Programming?
Definition
 Backpressure is a mechanism that allows a consumer (Subscriber) to
control the rate at which it receives data from a producer (Publisher).

 It prevents a fast producer from overwhelming a slow consumer.

 It is one of the core principles of the Reactive Streams


Specification.

 Backpressure ensures that systems remain stable, responsive, and


memory-efficient under heavy load.

Why Do We Need Backpressure?


Consider the following scenario:

Producer Speed : 10,000 records/second


Consumer Speed : 100 records/second

Without Backpressure:
Producer


10,000 records/sec


Consumer
100 records/sec

Problems
 Data accumulates in memory.

 Memory consumption continuously increases.

 Application may become slow.

 Garbage Collection pressure increases.

 OutOfMemoryError (OOM) may occur.

 System can eventually crash.

Real-World Analogy
Restaurant Order System

Imagine:

Chef (Producer)


Waiter (Consumer)

Scenario Without Backpressure

 Chef prepares 100 dishes every minute.

 Waiter can serve only 20 dishes every minute.

 Dishes begin piling up in the kitchen.

 Space runs out.

 Operations become inefficient.

Scenario With Backpressure

The waiter informs the chef:

Please prepare only 20 dishes at a time.


Now:

 No overload occurs.

 No unnecessary accumulation happens.

 The workflow remains balanced.

This is exactly how backpressure works in Reactive Streams.

Backpressure in Reactive Streams


Reactive Streams defines four major components:

Publisher
Subscriber
Subscription
Processor

Backpressure is implemented through the interaction between:

Publisher


Subscription


Subscriber

The Subscriber controls the flow of data using the Subscription.

How Backpressure Works


Step 1: Subscriber subscribes.
Subscriber


Publisher

Step 2: Publisher creates Subscription.


Publisher


Subscription

Step 3:Subscriber requests data.


request(5)
Step 4:Publisher sends only 5 items.
Step 5: Subscriber processes data.
Step 6: Subscriber requests more.
request(5)

Publisher sends next batch.

Backpressure Strategies in Reactor


When producer is faster than consumer, Reactor provides several strategies.

1. Buffer Strategy
Method
onBackpressureBuffer()

Behavior
Producer → Buffer → Consumer

Items are stored temporarily.

Example
[Link]([Link](1))
.onBackpressureBuffer();

Advantages
 No data loss.

 Reliable delivery.

Disadvantages
 Increased memory usage.

 Risk of OutOfMemoryError.

2. Drop Strategy
Method
onBackpressureDrop()
Behavior
Drops excess items.
Producer

100 items

Consumer handles 20
Remaining 80 dropped
Example
[Link]([Link](1))
.onBackpressureDrop();

Advantages
 Low memory usage.

 High throughput.

Disadvantages
 Data loss.

3. Latest Strategy
Method
onBackpressureLatest()

Behavior
Keeps only the latest item.

Example:

Received:
12345678

Consumer ready

Gets only:
8

Use Cases
 Sensor readings.

 Live dashboards.

 Stock prices.

4. Error Strategy
Method
onBackpressureError()
Behavior
Throws exception when consumer cannot keep up.
Example
[Link]([Link](1))
.onBackpressureError();
Use Cases
 Critical systems.

 Strict processing requirements.

Request-Based Backpressure
Subscriber can request specific number of items.
Example:
request(10);
Publisher sends:
10 items only
This is called Demand-Driven Processing.

Benefits of Backpressure
Resource Protection
 Prevents memory overflow.

 Avoids excessive CPU utilization.

Improved Stability
 Prevents system crashes.

 Maintains responsiveness.

Better Throughput
 Controlled data flow.

 Efficient processing.

Scalability
 Handles millions of events efficiently.

 Suitable for distributed systems.

Non-Blocking Communication
 No thread blocking.

 Event-driven processing.
Concurrency in Reactive Systems
What is Concurrency?
 Concurrency is the ability of a system to handle multiple tasks, requests, or events at the
same time.
 In a reactive system, concurrency is achieved without creating a dedicated thread for
every request.
 Instead of blocking threads while waiting for I/O operations, reactive systems use
asynchronous, event-driven processing.
 Concurrency allows applications to efficiently utilize CPU and system resources while
serving many clients simultaneously.

Traditional Concurrency Model (Thread-Per-Request)


In traditional web applications:
Request 1 → Thread 1
Request 2 → Thread 2
Request 3 → Thread 3
...
Request N → Thread N
Example
@GetMapping("/employees/{id}")
public Employee getEmployee(Long id) {
return [Link](id);
}
What Happens?
 A thread receives the request.
 Thread calls the database.
 Thread waits until the database responds.
 During the wait period, the thread remains blocked.
 The thread cannot perform any other work.
Problems
 High memory consumption.
 Excessive thread creation.
 Context-switching overhead.
 Thread pool exhaustion.
 Reduced scalability under heavy load.

Reactive Concurrency Model


Reactive systems use:
Few Threads


Many Concurrent Requests
Instead of:
1 Request = 1 Thread
Reactive systems use:
Many Requests = Few Event Loop Threads

Event Loop Architecture


Reactive frameworks such as Project Reactor and Spring WebFlux use an event loop model.
Request


Event Loop Thread


Non-Blocking Operation


Continue Processing Other Requests
Key Idea
 Threads never wait for I/O operations.
 Threads are immediately released to process other tasks.
 When data becomes available, the event loop resumes processing.
Example of Non-Blocking Database Call
@GetMapping("/employees/{id}")
public Mono<Employee> getEmployee(Long id) {
return [Link](id);
}
Flow
Client Request


Event Loop Thread


Database Query Sent


Thread Released


Database Responds Later


Response Sent To Client
Result
 Thread is not blocked.
 Same thread can process other requests.
 Better scalability.

How Concurrency Works in Project Reactor


Project Reactor uses:
 Asynchronous execution.
 Event-driven processing.
 Non-blocking I/O.
 Schedulers.
 Reactive Streams.

Scheduler-Based Concurrency
Schedulers control where tasks execute.
[Link](1, 10)
.subscribeOn([Link]())
.subscribe([Link]::println);
Purpose
 Moves execution to a thread pool.
 Enables concurrent processing.
 Optimizes resource usage.

Types of Schedulers in Reactor


1. [Link]()
Characteristics
 Executes on the current thread.
 No thread switching.
Example
[Link]("Java")
.subscribeOn([Link]());
Use Cases
 Lightweight operations.
 Testing.

2. [Link]()
Characteristics
 Uses one dedicated thread.
 Sequential execution.
Example
[Link](1,5)
.publishOn([Link]());
Use Cases
 Ordered processing.
 State-sensitive operations.

3. [Link]()
Characteristics
 Uses a fixed-size thread pool.
 Number of threads ≈ CPU cores.
Example
[Link](1,100)
.parallel()
.runOn([Link]())
.subscribe();
Use Cases
 CPU-intensive calculations.
 Data transformation.
 Parallel processing.

4. [Link]()
Characteristics
 Dynamic thread pool.
 Designed for blocking operations.
Example
[Link](this::readFile)
.subscribeOn([Link]());
Use Cases
 File access.
 JDBC operations.
 Legacy blocking APIs.

subscribeOn() vs publishOn()
These are the most important methods for concurrency control.

subscribeOn()
Purpose
 Determines where the source starts execution.
Example
[Link]("Spring")
.subscribeOn([Link]());
Flow
Source Execution


Parallel Thread

publishOn()
Purpose
 Changes thread execution for downstream operators.
Example
[Link](1,5)
.publishOn([Link]())
.map(i -> i * 10);
Flow
Source Thread

publishOn()


Parallel Thread

You might also like