Repository: iluwatar/java-design-patterns
Pull request #3249: Adding backpressure design pattern #3233
Author: login: sanurah
Labels: name: status: under review
Created: 2025-04-09T21:32:54Z | Merged: 2025-04-12T05:46:49Z

# Pull Request Template

## What does this PR do?

This PR is adding the backpressure design pattern
 Relates to #3233



Diff:
diff --git a/backpressure/README.md b/backpressure/README.md
new file mode 100644
index 000000000000..51a0307e17f6
--- /dev/null
+++ b/backpressure/README.md
@@ -0,0 +1,221 @@
+---
+title: "Backpressure Pattern in Java: controlling data streams from producers to consumer inorder to prevent overwhelming the consumer"
+shortTitle: Backpressure
+description: "Explore the Backpressure design pattern in Java with detailed examples. Learn how it helps by preventing system overload, ensuring stability and optimal performance by matching data flow to the consumer’s processing capability."
+category: Concurrency
+language: en
+tag:
+    - Decoupling
+    - Event-driven
+    - Reactive
+---
+
+## Intent of the Backpressure Design Pattern
+
+The Backpressure Design Pattern is a strategy used in software systems (especially in data streaming, reactive programming, and distributed systems) 
+to handle situations where a fast producer overwhelms a slow consumer. The intent is to prevent system instability, resource exhaustion, or crashes by managing the flow of data between components.
+
+## Detailed Explanation of Backpressure Pattern with Real-World Examples
+
+### Real-world examples
+
+#### 1. Real-Time Data Streaming (Reactive Systems)
+- **Stock Market Data**
+  - High-frequency trading systems generate millions of price updates per second, but analytics engines can't process them all in real time.
+  - Backpressure mechanisms (e.g., in RxJava, Akka, Reactor) throttle or drop excess data to avoid overwhelming downstream systems.
+- **IoT Sensor DataQ**
+  - Thousands of IoT devices (e.g., smart factories, wearables) send continuous telemetry, but cloud processing has limited capacity.
+  - Reactive frameworks apply backpressure to buffer, drop, or slow down data emission.
+
+#### 2. Message Queues (Kafka, RabbitMQ)
+- **E-Commerce Order Processing**
+    - During flash sales (e.g., Black Friday), order requests spike, but payment and inventory systems can’t keep up.
+    - Message queues like Kafka and RabbitMQ use, Limited queue sizes to drop or reject messages when full or Consumer acknowledgments to slow producers if consumers lag.
+- **Log Aggregation**
+    - Microservices generate massive logs, but centralized logging (E.g.: ELK Stack) can’t ingest them all at once.
+    - Kafka applies backpressure by pausing producers when consumers are slow.
+
+#### 3. Stream Processing (Apache Flink, Spark)
+- **Social Media Trends (Twitter, TikTok)**
+    - Viral posts create sudden spikes in data, but trend analysis is computationally expensive.
+    - Backpressure in Spark Streaming prioritizes recent data and discards older, less relevant updates.
+- **Fraud Detection in Banking**
+    - Millions of transactions flow in, but fraud detection models take time to analyze each one.
+    - slow down ingestion if processing lags (Throttling), save progress to recover from backpressure-induced delays (Checkpointing).
+
+### In plain words
+
+The Backpressure design pattern is a flow control mechanism that prevents overwhelming a system by regulating data production based on the consumer’s processing capacity.
+
+### Wikipedia says
+
+Back pressure (or backpressure) is the term for a resistance to the desired flow of fluid through pipes. Obstructions or tight bends create backpressure via friction loss and pressure drop.
+
+In distributed systems in particular event-driven architecture, back pressure is a technique to regulate flow of data, ensuring that components do not become overwhelmed.
+
+### Architectural Diagram
+![backpressure](./etc/backpressure.png)
+
+## Programmatic Example of Backpressure Pattern in Java
+
+First we will create a publisher that generates a data stream.
+This publisher can generate a stream of integers.
+
+```java
+public class Publisher {
+    public static Flux<Integer> publish(int start, int count, int delay) {
+        return Flux.range(start, count).delayElements(Duration.ofMillis(delay)).log();
+    }
+}
+```
+
+Then we can create a custom subscriber based on reactor BaseSubscriber.
+It will take 500ms to process one item to simulate slow processing.
+This subscriber will override following methods to apply backpressure on the publisher.
+- hookOnSubscribe method and initially request for 10 items
+- hookOnNext method which will process 5 items and request for 5 more items
+
+```java
+public class Subscriber extends BaseSubscriber<Integer> {
+
+    private static final Logger logger = LoggerFactory.getLogger(Subscriber.class);
+
+    @Override
+    protected void hookOnSubscribe(@NonNull Subscription subscription) {
+        logger.info("subscribe()");
+        request(10); //request 10 items initially
+    }
+
+    @Override
+    protected void hookOnNext(@NonNull Integer value) {
+        processItem();
+        logger.info("process({})", value);
+        if (value % 5 == 0) {
+            // request for the next 5 items after processing first 5
+            request(5);
+        }
+    }
+
+    @Override
+    protected void hookOnComplete() {
+        //completed processing.
+    }
+
+    private void processItem() {
+        try {
+            Thread.sleep(500); // simulate slow processing
+        } catch (InterruptedException e) {
+            logger.error(e.getMessage(), e);
+        }
+    }
+}
+```
+
+Then we can create the stream using the publisher and subscribe to that stream.
+
+```java
+public static void main(String[] args) throws InterruptedException {
+    Subscriber sub = new Subscriber();
+    Publisher.publish(1, 8, 200).subscribe(sub);
+    Thread.sleep(5000); //wait for execution
+    
+}
+```
+
+Program output:
+
+```
+23:09:55.746 [main] DEBUG reactor.util.Loggers -- Using Slf4j logging framework
+23:09:55.762 [main] INFO reactor.Flux.ConcatMapNoPrefetch.1 -- onSubscribe(FluxConcatMapNoPrefetch.FluxConcatMapNoPrefetchSubscriber)
+23:09:55.762 [main] INFO com.iluwatar.backpressure.Subscriber -- subscribe()
+23:09:55.763 [main] INFO reactor.Flux.ConcatMapNoPrefetch.1 -- request(10)
+23:09:55.969 [parallel-1] INFO reactor.Flux.ConcatMapNoPrefetch.1 -- onNext(1)
+23:09:56.475 [parallel-1] INFO com.iluwatar.backpressure.Subscriber -- process(1)
+23:09:56.680 [parallel-2] INFO reactor.Flux.ConcatMapNoPrefetch.1 -- onNext(2)
+23:09:57.185 [parallel-2] INFO com.iluwatar.backpressure.Subscriber -- process(2)
+23:09:57.389 [parallel-3] INFO reactor.Flux.ConcatMapNoPrefetch.1 -- onNext(3)
+23:09:57.894 [parallel-3] INFO com.iluwatar.backpressure.Subscriber -- process(3)
+23:09:58.099 [parallel-4] INFO reactor.Flux.ConcatMapNoPrefetch.1 -- onNext(4)
+23:09:58.599 [parallel-4] INFO com.iluwatar.backpressure.Subscriber -- process(4)
+23:09:58.805 [parallel-5] INFO reactor.Flux.ConcatMapNoPrefetch.1 -- onNext(5)
+23:09:59.311 [parallel-5] INFO com.iluwatar.backpressure.Subscriber -- process(5)
+23:09:59.311 [parallel-5] INFO reactor.Flux.ConcatMapNoPrefetch.1 -- request(5)
+23:09:59.516 [parallel-6] INFO reactor.Flux.ConcatMapNoPrefetch.1 -- onNext(6)
+23:10:00.018 [parallel-6] INFO com.iluwatar.backpressure.Subscriber -- process(6)
+23:10:00.223 [parallel-7] INFO reactor.Flux.ConcatMapNoPrefetch.1 -- onNext(7)
+23:10:00.729 [parallel-7] INFO com.iluwatar.backpressure.Subscriber -- process(7)
+23:10:00.930 [parallel-8] INFO reactor.Flux.ConcatMapNoPrefetch.1 -- onNext(8)
+23:10:01.436 [parallel-8] INFO com.iluwatar.backpressure.Subscriber -- process(8)
+23:10:01.437 [parallel-8] INFO reactor.Flux.ConcatMapNoPrefetch.1 -- onComplete()
+```
+
+## When to Use the Backpressure Pattern
+
+- Producers Are Faster Than Consumers
+    - If a producer generates data at a much faster rate than the consumer can handle, backpressure prevents resource overload.
+    - Example: A server emitting events 10x faster than the client can process.
+
+- There’s Limited Memory or Resource Capacity
+    - Without flow control, queues or buffers can grow indefinitely, leading to out-of-memory errors or system crashes.
+    - Example: Streaming large datasets into a low-memory microservice.
+
+- Building Reactive or Event-Driven Architectures
+    - Reactive systems thrive on non-blocking, asynchronous flows—and backpressure is a core component of the Reactive Streams specification.
+    - Example: Using RxJava, Project Reactor, Akka Streams, or Node.js streams.
+
+- Unpredictable Workloads
+    - If the rate of data production or consumption can vary, backpressure helps adapt dynamically.
+    - Example: APIs receiving unpredictable spikes in traffic.
+
+- Need to Avoid Data Loss or Overflow
+    - Instead of dropping data arbitrarily, backpressure lets you control flow intentionally.
+    - Example: Video or audio processing pipelines where dropping frames is costly.
+
+## When to avoid the Backpressure Pattern
+
+- For batch processing or simple linear flows with well-matched speeds.
+- If data loss is acceptable and simpler strategies like buffering or throttling are easier to manage.
+- When using fire-and-forget patterns (e.g., log shipping with retries instead of slowing the producer).
+
+## Benefits and Trade-offs of Backpressure Pattern
+
+### Benefits:
+
+-  Improved System Stability
+    - Prevents overload by controlling data flow.
+    - Reduces chances of out-of-memory errors, thread exhaustion, or service crashes.
+- Efficient Resource Usage
+    - Avoids excessive buffering and unnecessary computation.
+    - Enables systems to do only the work they can handle.
+- Better Responsiveness
+    - Keeps queues short, which improves latency and throughput.
+    - More consistent performance under load.
+- Graceful Degradation
+    - If the system can't keep up, it slows down cleanly rather than failing unpredictably.
+    - Consumers get a chance to control the pace, leading to predictable behavior.
+- Fits Reactive Programming
+    - It's essential in Reactive Streams, RxJava, Project Reactor, and Akka Streams.
+    - Enables composing async streams safely and effectively.
+
+### Trade-offs:
+
+- Complexity in Debugging
+    - Adds logic for flow control, demand signaling, and failure handling.
+    - More state to manage (e.g., request counts, pause/resume, buffer sizes).
+- Harder Debugging & Testing
+    - Asynchronous flow + demand coordination = trickier to test and debug.
+    - Race conditions or deadlocks may occur if not handled carefully.
+- Potential for Bottlenecks
+    - A slow consumer can throttle the entire system, even if other parts are fast.
+    - Needs smart handling (e.g., buffer + drop + retry strategies).
+
+## Related Java Design Patterns
+* [Publish-Subscribe Pattern](https://github.com/sanurah/java-design-patterns/blob/master/publish-subscribe/): Pub-Sub pattern decouples producers from consumers so they can communicate without knowing about each other. Backpressure manages flow control between producer and consumer to avoid overwhelming the consumer.
+* [Observer Pattern](https://github.com/sanurah/java-design-patterns/blob/master/observer/): Both involve a producer (subject/publisher) notifying consumers (observers/subscribers). Observer is synchronous & tightly coupled (observers know the subject). Pub-Sub is asynchronous & decoupled (via a message broker).
+* [Mediator Pattern](https://github.com/sanurah/java-design-patterns/blob/master/mediator/): A mediator centralizes communication between components (like a message broker in Pub-Sub). Mediator focuses on reducing direct dependencies between objects. Pub-Sub focuses on broadcasting events to unknown subscribers.
+
+## References and Credits
+
+* [Reactive Streams Specification](https://www.reactive-streams.org/)
+* [Reactive Programming with RxJava by Tomasz Nurkiewicz & Ben Christensen](https://www.oreilly.com/library/view/reactive-programming-with/9781491931646/)
+* [RedHat Developers Blog](https://developers.redhat.com/articles/backpressure-explained)
diff --git a/backpressure/etc/backpressure.png b/backpressure/etc/backpressure.png
new file mode 100644
index 000000000000..0de9ff54b673
Binary files /dev/null and b/backpressure/etc/backpressure.png differ
diff --git a/backpressure/pom.xml b/backpressure/pom.xml
new file mode 100644
index 000000000000..8807f0faf2b4
--- /dev/null
+++ b/backpressure/pom.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.iluwatar</groupId>
+        <artifactId>java-design-patterns</artifactId>
+        <version>1.26.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>backpressure</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.projectreactor</groupId>
+            <artifactId>reactor-core</artifactId>
+            <version>3.8.0-M1</version>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.projectreactor</groupId>
+            <artifactId>reactor-test</artifactId>
+            <version>3.8.0-M1</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <configuration>
+                            <archive>
+                                <manifest>
+                                    <mainClass>com.iluwatar.backpressure.App</mainClass>
+                                </manifest>
+                            </archive>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/backpressure/src/main/java/com/iluwatar/backpressure/App.java b/backpressure/src/main/java/com/iluwatar/backpressure/App.java
new file mode 100644
index 000000000000..4632c42a467f
--- /dev/null
+++ b/backpressure/src/main/java/com/iluwatar/backpressure/App.java
@@ -0,0 +1,76 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.backpressure;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * The Backpressure pattern is a flow control mechanism. It allows a consumer to signal to a
+ * producer to slow down or stop sending data when it's overwhelmed.
+ * <li>Prevents memory overflow, CPU thrashing, and resource exhaustion.
+ * <li>Ensures fair usage of resources in distributed systems.
+ * <li>Avoids buffer bloat and latency spikes. Key concepts of this design paradigm involves
+ * <li>Publisher/Producer: Generates data.
+ * <li>Subscriber/Consumer: Receives and processes data.
+ *
+ *     <p>In this example we will create a {@link Publisher} and a {@link Subscriber}. Publisher
+ *     will emit a stream of integer values with a predefined delay. Subscriber takes 500 ms to
+ *     process one integer. Since the subscriber can't process the items fast enough we apply
+ *     backpressure to the publisher so that it will request 10 items first, process 5 items and
+ *     request for the next 5 again. After processing 5 items subscriber will keep requesting for
+ *     another 5 until the stream ends.
+ */
+public class App {
+
+  protected static CountDownLatch latch;
+
+  /**
+   * Program entry point.
+   *
+   * @param args command line args
+   */
+  public static void main(String[] args) throws InterruptedException {
+
+    /*
+     * This custom subscriber applies backpressure:
+     * - Has a processing delay of 0.5 milliseconds
+     * - Requests 10 items initially
+     * - Process 5 items and request for the next 5 items
+     */
+    Subscriber sub = new Subscriber();
+    // slow publisher emit 15 numbers with a delay of 200 milliseconds
+    Publisher.publish(1, 17, 200).subscribe(sub);
+
+    latch = new CountDownLatch(1);
+    latch.await();
+
+    sub = new Subscriber();
+    // fast publisher emit 15 numbers with a delay of 1 millisecond
+    Publisher.publish(1, 17, 1).subscribe(sub);
+
+    latch = new CountDownLatch(1);
+    latch.await();
+  }
+}
diff --git a/backpressure/src/main/java/com/iluwatar/backpressure/Publisher.java b/backpressure/src/main/java/com/iluwatar/backpressure/Publisher.java
new file mode 100644
index 000000000000..20fbd31f60a1
--- /dev/null
+++ b/backpressure/src/main/java/com/iluwatar/backpressure/Publisher.java
@@ -0,0 +1,44 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.backpressure;
+
+import java.time.Duration;
+import reactor.core.publisher.Flux;
+
+/** This class is the publisher that generates the data stream. */
+public class Publisher {
+
+  /**
+   * On message method will trigger when the subscribed event is published.
+   *
+   * @param start starting integer
+   * @param count how many integers to emit
+   * @param delay delay between each item in milliseconds
+   * @return a flux stream of integers
+   */
+  public static Flux<Integer> publish(int start, int count, int delay) {
+    return Flux.range(start, count).delayElements(Duration.ofMillis(delay)).log();
+  }
+}
diff --git a/backpressure/src/main/java/com/iluwatar/backpressure/Subscriber.java b/backpressure/src/main/java/com/iluwatar/backpressure/Subscriber.java
new file mode 100644
index 000000000000..40ff5aebc814
--- /dev/null
+++ b/backpressure/src/main/java/com/iluwatar/backpressure/Subscriber.java
@@ -0,0 +1,64 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.backpressure;
+
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+import org.reactivestreams.Subscription;
+import reactor.core.publisher.BaseSubscriber;
+
+/** This class is the custom subscriber that subscribes to the data stream. */
+@Slf4j
+public class Subscriber extends BaseSubscriber<Integer> {
+
+  @Override
+  protected void hookOnSubscribe(@NonNull Subscription subscription) {
+    request(10); // request 10 items initially
+  }
+
+  @Override
+  protected void hookOnNext(@NonNull Integer value) {
+    processItem();
+    LOGGER.info("process({})", value);
+    if (value % 5 == 0) {
+      // request for the next 5 items after processing first 5
+      request(5);
+    }
+  }
+
+  @Override
+  protected void hookOnComplete() {
+    App.latch.countDown();
+  }
+
+  private void processItem() {
+    try {
+      Thread.sleep(500); // simulate slow processing
+    } catch (InterruptedException e) {
+      LOGGER.error(e.getMessage(), e);
+      Thread.currentThread().interrupt();
+    }
+  }
+}
diff --git a/backpressure/src/test/java/com/iluwatar/backpressure/AppTest.java b/backpressure/src/test/java/com/iluwatar/backpressure/AppTest.java
new file mode 100644
index 000000000000..8fe2245a97b7
--- /dev/null
+++ b/backpressure/src/test/java/com/iluwatar/backpressure/AppTest.java
@@ -0,0 +1,37 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.backpressure;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+import org.junit.jupiter.api.Test;
+
+public class AppTest {
+
+  @Test
+  void shouldExecuteApplicationWithoutException() {
+    assertDoesNotThrow(() -> App.main(new String[] {}));
+  }
+}
diff --git a/backpressure/src/test/java/com/iluwatar/backpressure/LoggerExtension.java b/backpressure/src/test/java/com/iluwatar/backpressure/LoggerExtension.java
new file mode 100644
index 000000000000..e99926e00a1a
--- /dev/null
+++ b/backpressure/src/test/java/com/iluwatar/backpressure/LoggerExtension.java
@@ -0,0 +1,60 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.backpressure;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.slf4j.LoggerFactory;
+
+public class LoggerExtension implements BeforeEachCallback, AfterEachCallback {
+
+  private final ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
+  private final Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+
+  @Override
+  public void afterEach(ExtensionContext extensionContext) {
+    listAppender.stop();
+    listAppender.list.clear();
+    logger.detachAppender(listAppender);
+  }
+
+  @Override
+  public void beforeEach(ExtensionContext extensionContext) {
+    logger.addAppender(listAppender);
+    listAppender.start();
+  }
+
+  public List<String> getFormattedMessages() {
+    return listAppender.list.stream()
+        .map(ILoggingEvent::getFormattedMessage)
+        .collect(Collectors.toList());
+  }
+}
diff --git a/backpressure/src/test/java/com/iluwatar/backpressure/PublisherTest.java b/backpressure/src/test/java/com/iluwatar/backpressure/PublisherTest.java
new file mode 100644
index 000000000000..010a80e83959
--- /dev/null
+++ b/backpressure/src/test/java/com/iluwatar/backpressure/PublisherTest.java
@@ -0,0 +1,51 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.backpressure;
+
+import static com.iluwatar.backpressure.Publisher.publish;
+
+import java.time.Duration;
+import org.junit.jupiter.api.Test;
+import reactor.core.publisher.Flux;
+import reactor.test.StepVerifier;
+
+public class PublisherTest {
+
+  @Test
+  public void testPublish() {
+
+    Flux<Integer> flux = publish(1, 3, 200);
+
+    StepVerifier.withVirtualTime(() -> flux)
+        .expectSubscription()
+        .expectNoEvent(Duration.ofMillis(200))
+        .expectNext(1)
+        .expectNoEvent(Duration.ofSeconds(200))
+        .expectNext(2)
+        .expectNoEvent(Duration.ofSeconds(200))
+        .expectNext(3)
+        .verifyComplete();
+  }
+}
diff --git a/backpressure/src/test/java/com/iluwatar/backpressure/SubscriberTest.java b/backpressure/src/test/java/com/iluwatar/backpressure/SubscriberTest.java
new file mode 100644
index 000000000000..7f7676612d02
--- /dev/null
+++ b/backpressure/src/test/java/com/iluwatar/backpressure/SubscriberTest.java
@@ -0,0 +1,54 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.backpressure;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.concurrent.CountDownLatch;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public class SubscriberTest {
+
+  @RegisterExtension public LoggerExtension loggerExtension = new LoggerExtension();
+
+  @Test
+  public void testSubscribe() throws InterruptedException {
+
+    Subscriber sub = new Subscriber();
+    Publisher.publish(1, 8, 100).subscribe(sub);
+
+    App.latch = new CountDownLatch(1);
+    App.latch.await();
+
+    String result = String.join(",", loggerExtension.getFormattedMessages());
+    assertTrue(
+        result.endsWith(
+            "onSubscribe(FluxConcatMapNoPrefetch."
+                + "FluxConcatMapNoPrefetchSubscriber),request(10),onNext(1),process(1),onNext(2),"
+                + "process(2),onNext(3),process(3),onNext(4),process(4),onNext(5),process(5),request(5),"
+                + "onNext(6),process(6),onNext(7),process(7),onNext(8),process(8),onComplete()"));
+  }
+}
diff --git a/pom.xml b/pom.xml
index fb0bfd7565e1..13dd8eaa02b1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -242,6 +242,7 @@
     <module>version-number</module>
     <module>virtual-proxy</module>
     <module>visitor</module>
+      <module>backpressure</module>
   </modules>
   <repositories>
     <repository>


Reviews:
user: login: github-actions[bot]
body: ✅ **LGTM!**

### Review Summary

<details>
<summary>Commits Considered (3)</summary>

- [7c3ba8a](https://github.com/iluwatar/java-design-patterns/commit/7c3ba8ad11bdbf3b826e6df269211f33bdc9a3b9): Merge branch 'iluwatar:master' into master
- [1fa515f](https://github.com/iluwatar/java-design-patterns/commit/1fa515fe41eef15e93d9e3c34114e4e1cdd36662): Adding backpressure pattern #3233
- [b8f51f0](https://github.com/iluwatar/java-design-patterns/commit/b8f51f09e2d3d26fe2d64b8d224ca03976260a91): Initial commit backpressure

temp

</details>

<details>
<summary>Files Processed (11)</summary>

- backpressure/README.md _(1 hunk)_
- backpressure/etc/backpressure.png _(0 hunks)_
- backpressure/pom.xml _(1 hunk)_
- backpressure/src/main/java/com/iluwatar/backpressure/App.java _(1 hunk)_
- backpressure/src/main/java/com/iluwatar/backpressure/Publisher.java _(1 hunk)_
- backpressure/src/main/java/com/iluwatar/backpressure/Subscriber.java _(1 hunk)_
- backpressure/src/test/java/com/iluwatar/backpressure/AppTest.java _(1 hunk)_
- backpressure/src/test/java/com/iluwatar/backpressure/LoggerExtension.java _(1 hunk)_
- backpressure/src/test/java/com/iluwatar/backpressure/PublisherTest.java _(1 hunk)_
- backpressure/src/test/java/com/iluwatar/backpressure/SubscriberTest.java _(1 hunk)_
- pom.xml _(1 hunk)_

</details>

<details>
<summary>Actionable Comments (0)</summary>


</details>

<details>
<summary>Skipped Comments (0)</summary>

</details>


state: COMMENTED
author_association: NONE
submitted_at: 2025-04-09T21:33:18Z
user: login: github-actions[bot]
body: ✅ **LGTM!**

### Review Summary

<details>
<summary>Commits Considered (1)</summary>

- [b85de31](https://github.com/iluwatar/java-design-patterns/commit/b85de31719b55954a8cf043215539822c46ffd88): Fix test case #3233

</details>

<details>
<summary>Files Processed (10)</summary>

- backpressure/README.md _(1 hunk)_
- backpressure/pom.xml _(1 hunk)_
- backpressure/src/main/java/com/iluwatar/backpressure/App.java _(1 hunk)_
- backpressure/src/main/java/com/iluwatar/backpressure/Publisher.java _(1 hunk)_
- backpressure/src/main/java/com/iluwatar/backpressure/Subscriber.java _(1 hunk)_
- backpressure/src/test/java/com/iluwatar/backpressure/AppTest.java _(1 hunk)_
- backpressure/src/test/java/com/iluwatar/backpressure/LoggerExtension.java _(1 hunk)_
- backpressure/src/test/java/com/iluwatar/backpressure/PublisherTest.java _(1 hunk)_
- backpressure/src/test/java/com/iluwatar/backpressure/SubscriberTest.java _(1 hunk)_
- pom.xml _(1 hunk)_

</details>

<details>
<summary>Actionable Comments (0)</summary>


</details>

<details>
<summary>Skipped Comments (0)</summary>

</details>


state: COMMENTED
author_association: NONE
submitted_at: 2025-04-09T22:37:57Z
user: login: github-actions[bot]
body: ✅ **LGTM!**

### Review Summary

<details>
<summary>Commits Considered (1)</summary>

- [4552f83](https://github.com/iluwatar/java-design-patterns/commit/4552f83bb368e1b038e3b5469cb6d14fa400fe5e): Fix formatting #3233

</details>

<details>
<summary>Files Processed (5)</summary>

- backpressure/src/main/java/com/iluwatar/backpressure/App.java _(1 hunk)_
- backpressure/src/main/java/com/iluwatar/backpressure/Publisher.java _(1 hunk)_
- backpressure/src/main/java/com/iluwatar/backpressure/Subscriber.java _(1 hunk)_
- backpressure/src/test/java/com/iluwatar/backpressure/PublisherTest.java _(1 hunk)_
- backpressure/src/test/java/com/iluwatar/backpressure/SubscriberTest.java _(1 hunk)_

</details>

<details>
<summary>Actionable Comments (0)</summary>


</details>

<details>
<summary>Skipped Comments (1)</summary>

- <details>
  <summary>backpressure/src/main/java/com/iluwatar/backpressure/Subscriber.java [36-42]</summary>

  > performance: "Inefficient delay simulation in `processItem` method."
  </details>
</details>


state: COMMENTED
author_association: NONE
submitted_at: 2025-04-10T15:49:22Z
user: login: iluwatar
state: CHANGES_REQUESTED
author_association: OWNER
submitted_at: 2025-04-10T16:47:23Z
user: login: github-actions[bot]
body: ✅ **LGTM!**

### Review Summary

<details>
<summary>Commits Considered (1)</summary>

- [58af7b3](https://github.com/iluwatar/java-design-patterns/commit/58af7b3b9bde904664c4b05352304beb126ac398): Changes after review #3233

</details>

<details>
<summary>Files Processed (8)</summary>

- backpressure/pom.xml _(1 hunk)_
- backpressure/src/main/java/com/iluwatar/backpressure/App.java _(1 hunk)_
- backpressure/src/main/java/com/iluwatar/backpressure/Publisher.java _(1 hunk)_
- backpressure/src/main/java/com/iluwatar/backpressure/Subscriber.java _(1 hunk)_
- backpressure/src/test/java/com/iluwatar/backpressure/AppTest.java _(1 hunk)_
- backpressure/src/test/java/com/iluwatar/backpressure/LoggerExtension.java _(1 hunk)_
- backpressure/src/test/java/com/iluwatar/backpressure/PublisherTest.java _(1 hunk)_
- backpressure/src/test/java/com/iluwatar/backpressure/SubscriberTest.java _(1 hunk)_

</details>

<details>
<summary>Actionable Comments (0)</summary>


</details>

<details>
<summary>Skipped Comments (0)</summary>

</details>


state: COMMENTED
author_association: NONE
submitted_at: 2025-04-10T18:46:24Z
user: login: sanurah
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T18:48:32Z
user: login: github-actions[bot]
body: ✅ **LGTM!**

### Review Summary

<details>
<summary>Commits Considered (1)</summary>

- [36131dd](https://github.com/iluwatar/java-design-patterns/commit/36131dd374c71d39203a17eba1913ecee6eba6ed): Fix sonar error in leaderfollowers module #3233

</details>

<details>
<summary>Files Processed (1)</summary>

- leader-followers/src/main/java/com/iluwatar/leaderfollowers/App.java _(1 hunk)_

</details>

<details>
<summary>Actionable Comments (0)</summary>


</details>

<details>
<summary>Skipped Comments (1)</summary>

- <details>
  <summary>leader-followers/src/main/java/com/iluwatar/leaderfollowers/App.java [70-76]</summary>

  > best practice: "Resource Management Improvement"
  </details>
</details>


state: COMMENTED
author_association: NONE
submitted_at: 2025-04-11T18:38:36Z
user: login: github-actions[bot]
body: ✅ **LGTM!**

### Review Summary

<details>
<summary>Commits Considered (1)</summary>

- [817cfbc](https://github.com/iluwatar/java-design-patterns/commit/817cfbce86fba34f6297945b5e2da2378d01398f): Merge branch 'master' into master

</details>

<details>
<summary>Files Processed (0)</summary>


</details>

<details>
<summary>Actionable Comments (0)</summary>


</details>

<details>
<summary>Skipped Comments (0)</summary>

</details>


state: COMMENTED
author_association: NONE
submitted_at: 2025-04-11T19:02:04Z
user: login: iluwatar
state: COMMENTED
author_association: OWNER
submitted_at: 2025-04-12T05:43:40Z
user: login: iluwatar
state: APPROVED
author_association: OWNER
submitted_at: 2025-04-12T05:46:20Z

Review comments:
diff_hunk: @@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.iluwatar</groupId>
+        <artifactId>java-design-patterns</artifactId>
+        <version>1.26.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>backpressure</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.projectreactor</groupId>
+            <artifactId>reactor-core</artifactId>
+            <version>3.8.0-M1</version>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.projectreactor</groupId>
+            <artifactId>reactor-test</artifactId>
+            <version>3.8.0-M1</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
path: backpressure/pom.xml
user: login: iluwatar
body: Add maven assembly plugin, so that the code example can be executed from the command line. See the other patterns for an example.
created_at: 2025-04-10T16:44:29Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,43 @@
+package com.iluwatar.backpressure;
+
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+import org.reactivestreams.Subscription;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import reactor.core.publisher.BaseSubscriber;
+
+/** This class is the custom subscriber that subscribes to the data stream. */
+@Slf4j
+public class Subscriber extends BaseSubscriber<Integer> {
+
+  private static final Logger logger = LoggerFactory.getLogger(Subscriber.class);
path: backpressure/src/main/java/com/iluwatar/backpressure/Subscriber.java
user: login: iluwatar
body: No need to declare logger like this. With the Lombok annotation you automatically have LOGGER available.
created_at: 2025-04-10T16:46:07Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,64 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.backpressure;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.slf4j.LoggerFactory;
+
+public class LoggerExtension implements BeforeEachCallback, AfterEachCallback {
+
+  private final ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
+  private final Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
path: backpressure/src/test/java/com/iluwatar/backpressure/LoggerExtension.java
user: login: iluwatar
body: Use Lombok's logger
created_at: 2025-04-10T16:46:37Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,64 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.backpressure;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.slf4j.LoggerFactory;
+
+public class LoggerExtension implements BeforeEachCallback, AfterEachCallback {
+
+  private final ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
+  private final Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
path: backpressure/src/test/java/com/iluwatar/backpressure/LoggerExtension.java
user: login: sanurah
body: I'm fetching the root logger to assert the logged messages during unit test.
I could not change this one to Lombok.
created_at: 2025-04-10T18:48:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,64 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.backpressure;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.slf4j.LoggerFactory;
+
+public class LoggerExtension implements BeforeEachCallback, AfterEachCallback {
+
+  private final ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
+  private final Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
path: backpressure/src/test/java/com/iluwatar/backpressure/LoggerExtension.java
user: login: iluwatar
body: Ok, understood. This is fine.
created_at: 2025-04-12T05:43:40Z
author_association: OWNER

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-09T21:33:10Z
body: ## PR Summary

This PR implements the backpressure design pattern in Java using Reactor.  It includes a `Publisher` that generates a stream of integers, and a `Subscriber` that processes them with a simulated delay, demonstrating backpressure handling to prevent consumer overload.  The implementation uses Reactor's `BaseSubscriber` to control the request rate and prevent overwhelming the subscriber. The PR also includes comprehensive unit tests and documentation.

### Changes

| File | Summary |
|:----------|:---------------|
| `backpressure/README.md` | This file provides a comprehensive explanation of the Backpressure design pattern, including real-world examples, a detailed explanation, a programmatic example in Java using Reactor, and when to use or avoid this pattern.  It also includes diagrams and references. |
| `backpressure/etc/backpressure.png` | New file: Diagram showing the Backpressure pattern architecture. |
| `backpressure/pom.xml` | This file configures the Maven project dependencies, including Reactor and testing libraries. It also sets up the main class for execution. |
| `backpressure/src/main/java/com/iluwatar/backpressure/App.java` | This Java class serves as the main application entry point. It demonstrates the backpressure pattern by creating a publisher and subscriber, and then subscribing the subscriber to the publisher's stream. |
| `backpressure/src/main/java/com/iluwatar/backpressure/Publisher.java` | This Java class implements the Publisher, which generates a stream of integers with a configurable delay. It uses Reactor's `Flux` to create the stream. |
| `backpressure/src/main/java/com/iluwatar/backpressure/Subscriber.java` | This Java class implements the Subscriber, which processes the integer stream from the Publisher. It uses Reactor's `BaseSubscriber` to implement backpressure, requesting items in batches and simulating processing time. |
| `backpressure/src/test/java/com/iluwatar/backpressure/AppTest.java` | This Java class contains a unit test to verify that the main application runs without throwing any exceptions. |
| `backpressure/src/test/java/com/iluwatar/backpressure/LoggerExtension.java` | This Java class is a JUnit extension that captures log messages for testing purposes. It uses Logback to capture log events and provides methods to access them. |
| `backpressure/src/test/java/com/iluwatar/backpressure/PublisherTest.java` | This Java class contains unit tests for the Publisher class, verifying that it generates the expected stream of integers with the correct delays. |
| `backpressure/src/test/java/com/iluwatar/backpressure/SubscriberTest.java` | This Java class contains unit tests for the Subscriber class, verifying that it correctly processes the stream and applies backpressure. |
| `pom.xml` | Added a module for the `backpressure` example to the main `pom.xml` file. |
--- 
_autogenerated by [presubmit.ai](https://github.com/presubmit/ai-reviewer)_
<!-- presubmit.ai: overview message -->
<!-- presubmit.ai: payload --{"commits":["b8f51f09e2d3d26fe2d64b8d224ca03976260a91","1fa515fe41eef15e93d9e3c34114e4e1cdd36662","7c3ba8ad11bdbf3b826e6df269211f33bdc9a3b9","b85de31719b55954a8cf043215539822c46ffd88","4552f83bb368e1b038e3b5469cb6d14fa400fe5e","58af7b3b9bde904664c4b05352304beb126ac398","36131dd374c71d39203a17eba1913ecee6eba6ed","817cfbce86fba34f6297945b5e2da2378d01398f"]}
-- presubmit.ai: payload -->
author_association: NONE
user: login: iluwatar
created_at: 2025-04-10T16:42:09Z
body: Check out the Sonar issue
author_association: OWNER
user: login: sonarqubecloud[bot]
created_at: 2025-04-11T19:18:09Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns&pullRequest=3249) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [8 New issues](https://sonarcloud.io/project/issues?id=iluwatar_java-design-patterns&pullRequest=3249&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=iluwatar_java-design-patterns&pullRequest=3249&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=iluwatar_java-design-patterns&pullRequest=3249&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [81.1% Coverage on New Code](https://sonarcloud.io/component_measures?id=iluwatar_java-design-patterns&pullRequest=3249&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=iluwatar_java-design-patterns&pullRequest=3249&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns&pullRequest=3249)


author_association: NONE
user: login: iluwatar
created_at: 2025-04-12T05:49:44Z
body: Looks good! Thank you for the contribution 🎉

@all-contributors please add @sanurah for code
author_association: OWNER
user: login: allcontributors[bot]
created_at: 2025-04-12T05:49:47Z
body: @iluwatar 

@sanurah already contributed before to code
author_association: CONTRIBUTOR