<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gaurav Kumar Yadav</title>
    <description>The latest articles on DEV Community by Gaurav Kumar Yadav (@gaurav10610).</description>
    <link>https://dev.to/gaurav10610</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4203375%2F9141ad79-54c7-4265-abe6-32937c58c72e.jpg</url>
      <title>DEV Community: Gaurav Kumar Yadav</title>
      <link>https://dev.to/gaurav10610</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gaurav10610"/>
    <language>en</language>
    <item>
      <title>Why We Don’t Always Need Kafka: High-Throughput Background Queues in Spring Boot with Redis &amp; Virtual Threads</title>
      <dc:creator>Gaurav Kumar Yadav</dc:creator>
      <pubDate>Fri, 23 Oct 2026 20:28:43 +0000</pubDate>
      <link>https://dev.to/gaurav10610/why-we-dont-always-need-kafka-high-throughput-background-queues-in-spring-boot-with-redis--1i62</link>
      <guid>https://dev.to/gaurav10610/why-we-dont-always-need-kafka-high-throughput-background-queues-in-spring-boot-with-redis--1i62</guid>
      <description>&lt;p&gt;&lt;em&gt;By Gaurav Kumar Yadav • Canonical URL: &lt;a href="https://gaurav10610.github.io/oxmq/guide/spring-boot.html" rel="noopener noreferrer"&gt;https://gaurav10610.github.io/oxmq/guide/spring-boot.html&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Every engineering team eventually hits this architectural crossroads:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Our application needs background workers for payment processing, report generation, webhooks, and email notifications. What should we use?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Too often, the default answer is: &lt;strong&gt;"Let's spin up Apache Kafka."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Three months later, the team is wrestling with partition rebalances, consumer group lag, broker ZooKeeper/KRaft quorum tuning, and high AWS MSK bills—all for a workload that just needed reliable task retries, sliding-window rate limiting, and parent-child task workflows.&lt;/p&gt;

&lt;p&gt;If you don't need petabyte-scale append-only event streaming with weeks of historical replay, &lt;strong&gt;Kafka is often the wrong tool for task queues&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore how to build a modern, high-throughput distributed background processing engine in &lt;strong&gt;Spring Boot 3+&lt;/strong&gt; using &lt;strong&gt;Redis&lt;/strong&gt;, &lt;strong&gt;Java 21 Project Loom Virtual Threads&lt;/strong&gt;, and &lt;strong&gt;&lt;a href="https://github.com/gaurav10610/oxmq" rel="noopener noreferrer"&gt;OxMQ&lt;/a&gt;&lt;/strong&gt;—the Virtual Thread-native Java alternative to BullMQ.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Distributed Task Queue Dilemma in Java
&lt;/h2&gt;

&lt;p&gt;In Node.js, developers have &lt;a href="https://github.com/taskforcesh/bullmq" rel="noopener noreferrer"&gt;BullMQ&lt;/a&gt;—a battle-tested Redis queue that executes Lua scripts for atomic state transitions, supports delayed scheduling, sliding-window rate limiters, and parent-child DAG flows, with instant visibility via the open-source &lt;a href="https://github.com/felixmosh/bull-board" rel="noopener noreferrer"&gt;Bull-Board Web UI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In Java, teams typically faced frustrating trade-offs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;In-Memory &lt;code&gt;ExecutorService&lt;/code&gt;&lt;/strong&gt;: Fast, but loses all tasks on crash or pod restart. No distributed lock or cluster coordination.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spring &lt;code&gt;@Scheduled&lt;/code&gt; &amp;amp; DB polling (&lt;code&gt;db-scheduler&lt;/code&gt;, &lt;code&gt;shedlock&lt;/code&gt;)&lt;/strong&gt;: Great for simple crons, but database table polling collapses under 5,000+ jobs/s and creates high DB CPU contention.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redisson Queues&lt;/strong&gt;: Opaque Lua implementations, no parent-child DAG orchestration, and no out-of-the-box monitoring UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kafka / RabbitMQ&lt;/strong&gt;: Heavy operational overhead, lack of native token-bucket rate limiting per tenant, and complex delayed job retries (dead-letter exchange looping).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is why we built &lt;strong&gt;&lt;a href="https://github.com/gaurav10610/oxmq" rel="noopener noreferrer"&gt;OxMQ&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture: How OxMQ Works
&lt;/h2&gt;

&lt;p&gt;OxMQ executes BullMQ’s official &lt;strong&gt;49 battle-tested Lua scripts&lt;/strong&gt; directly inside Redis. This guarantees:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;100% Atomic State Transitions&lt;/strong&gt;: No race conditions between workers claiming tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Polyglot Cross-Talk&lt;/strong&gt;: A Node.js microservice can push jobs that Java workers consume, and vice-versa.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instant Bull-Board Web UI&lt;/strong&gt;: Point the open-source Bull-Board dashboard at your Redis instance to inspect queues, pause workers, and review failed jobs with zero Node.js code.
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    Client["Spring Boot 3 Producer\n@Autowired OxmqQueue"] --&amp;gt;|queue.add / addBulk| Redis[("Redis / KeyDB / Valkey Cluster\n49 BullMQ Lua Scripts")]

    subgraph OxMQCluster ["Distributed OxMQ Worker Pods (Loom Virtual Threads)"]
        W1["Worker Pod 1\n500 Virtual Threads\n(~1 KB Heap/task)"]
        W2["Worker Pod 2\n500 Virtual Threads\n(~1 KB Heap/task)"]
    end

    Redis --&amp;gt;|Atomic Dequeue\nmoveToActive.lua| W1
    Redis --&amp;gt;|Atomic Dequeue\nmoveToActive.lua| W2

    W1 --&amp;gt;|AIMD Dynamic Yield / Cooldown| CloudAPI["External Cloud / Partner API\n(HTTP 429 Sentinel)"]
    W2 --&amp;gt;|AIMD Dynamic Yield / Cooldown| CloudAPI

    Redis -.-&amp;gt;|Real-time Metrics| BB["Bull-Board Web UI\nQueue Depths &amp;amp; Latencies"]
    Redis -.-&amp;gt;|Prometheus Exporter| Grafana["Grafana Dashboards\nThroughput &amp;amp; JVM Heap"]&lt;/code&gt;&lt;/pre&gt;






&lt;h2&gt;
  
  
  1. Project Loom Virtual Threads: The Concurrency Breakthrough
&lt;/h2&gt;

&lt;p&gt;Before Java 21, running 500 concurrent worker threads meant allocating &lt;strong&gt;500 MB to 1 GB of OS stack memory&lt;/strong&gt; (each platform thread takes ~1 MB). When workers blocked on slow network calls (e.g. Stripe API, OpenAI, or database transactions), underlying OS carrier threads sat idle, wasting CPU cycles.&lt;/p&gt;

&lt;p&gt;With Java 21 Project Loom:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Virtual Threads are managed by the JVM, consuming &lt;strong&gt;only ~1 KB of heap memory&lt;/strong&gt; each.&lt;/li&gt;
&lt;li&gt;When an OxMQ worker blocks on network I/O, the JVM unmounts the virtual thread, freeing the carrier thread to execute other jobs.&lt;/li&gt;
&lt;li&gt;On benchmark tests, OxMQ sustains &lt;strong&gt;800+ concurrent workers&lt;/strong&gt; on a &lt;strong&gt;strictly flat 35 OS threads&lt;/strong&gt; under realistic 10ms I/O delays.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Spring Boot 3 Declarative Setup
&lt;/h2&gt;

&lt;p&gt;Getting started in Spring Boot takes under 2 minutes:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Add Dependency
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.github.gaurav10610&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;oxmq-spring-boot-starter&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.7.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Configure &lt;code&gt;application.yml&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;oxmq&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis://localhost:6379&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;billing-service&lt;/span&gt; &lt;span class="c1"&gt;# Multi-tenant context isolation&lt;/span&gt;
  &lt;span class="na"&gt;worker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;concurrency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;           &lt;span class="c1"&gt;# 50 Virtual Threads on Java 21+&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Produce Jobs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;OxmqQueue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PaymentRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;paymentQueue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processPayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Enqueue with exponential backoff &amp;amp; memory retention&lt;/span&gt;
        &lt;span class="n"&gt;paymentQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"charge-customer"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PaymentRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="nc"&gt;JobOptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;attempts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;backoff&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Backoff&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exponential&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// 1s, 2s, 4s, 8s&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;keepJobs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KeepJobs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// Prevent Redis RAM bloat&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Consume Jobs Declaratively
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentWorker&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@OxmqListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"billing-service:charge-customer"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;concurrency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;PaymentResult&lt;/span&gt; &lt;span class="nf"&gt;handlePayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Job&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PaymentRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;PaymentRequest&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getData&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Report progress in real-time to Redis &amp;amp; Bull-Board&lt;/span&gt;
        &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateProgress&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;paymentGateway&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getOrderId&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAmount&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Handling Cloud Throttling: The AIMD Adaptive Rate Limiter Plugin
&lt;/h2&gt;

&lt;p&gt;In modern microservices, external APIs (Microsoft Graph, Stripe, Shopify) enforce dynamic quotas and return &lt;code&gt;HTTP 429 Too Many Requests&lt;/code&gt; with a &lt;code&gt;Retry-After&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;OxMQ provides native &lt;strong&gt;Enterprise Interceptor Plugins&lt;/strong&gt; to solve this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;RateLimitSentinelPlugin&lt;/code&gt;&lt;/strong&gt;: Automatically catches &lt;code&gt;HTTP 429&lt;/code&gt;, extracts &lt;code&gt;Retry-After&lt;/code&gt;, and engages a distributed Redis lockout across all cluster pods. Upcoming jobs defer without burning retry attempts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;AdaptiveRateLimiterPlugin&lt;/code&gt;&lt;/strong&gt;: Uses TCP-style &lt;strong&gt;AIMD (Additive Increase, Multiplicative Decrease)&lt;/strong&gt; to tune concurrency dynamically:

&lt;ul&gt;
&lt;li&gt;On HTTP 429: Immediately halves capacity (&lt;code&gt;L(t+1) = max(L_min, ⌊L(t) × 0.5⌋)&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;On clean execution: Additively increases capacity (&lt;code&gt;L(t+1) = min(L_max, L(t) + 25 RUs)&lt;/code&gt;).
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Bean&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;JobInterceptor&lt;/span&gt; &lt;span class="nf"&gt;adaptiveRateLimiter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RedisClient&lt;/span&gt; &lt;span class="n"&gt;redisClient&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;AdaptiveRateLimiterPlugin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;minLimit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxLimit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dampingWindowMs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60_000&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Freeze upgrades during recovery to prevent flapping&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;redisClient&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;redisClient&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Performance Benchmarks: 10,001-Node DAG Trees
&lt;/h2&gt;

&lt;p&gt;In benchmark stress tests executing massive 10,001-node parent-child DAG dependency trees:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resolution Throughput&lt;/strong&gt;: &lt;strong&gt;2,645.1 jobs/sec&lt;/strong&gt; (resolved in 3.78s).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Peak Ingestion Rate&lt;/strong&gt;: &lt;strong&gt;~3,250 nodes/sec&lt;/strong&gt; (saturating Redis TCP buffer).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis Memory&lt;/strong&gt;: Asymptotically stabilizes at &lt;strong&gt;~904 Bytes per node&lt;/strong&gt; (~8.68 MB for 10,001 jobs).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Virtual Thread Overhead&lt;/strong&gt;: Flat 35 OS carrier threads.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full benchmark code and reproduction scripts are open-sourced in the repo.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Instant Bull-Board Web UI Integration
&lt;/h2&gt;

&lt;p&gt;You can spin up the open-source Bull-Board dashboard in Docker in seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;REDIS_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;localhost &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;REDIS_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;6379 &lt;span class="se"&gt;\&lt;/span&gt;
  felixmosh/bull-board
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;http://localhost:3000&lt;/code&gt; to immediately inspect queue depths, pause/resume workers, trigger manual retries, and review JSON stack traces.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion &amp;amp; Resources
&lt;/h2&gt;

&lt;p&gt;If you’re building distributed background processing in Java and want high performance without Kafka-level operational baggage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project Repository:&lt;/strong&gt; &lt;a href="https://github.com/gaurav10610/oxmq" rel="noopener noreferrer"&gt;github.com/gaurav10610/oxmq&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Official Documentation:&lt;/strong&gt; &lt;a href="https://gaurav10610.github.io/oxmq/" rel="noopener noreferrer"&gt;gaurav10610.github.io/oxmq&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maven Central:&lt;/strong&gt; &lt;code&gt;io.github.gaurav10610:oxmq:1.7.0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License:&lt;/strong&gt; 100% Free &amp;amp; Open Source (Apache 2.0 / MIT)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⭐ If you find OxMQ helpful, star the project on GitHub and let us know your feedback!&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>redis</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
