<script data-pm-proxy="intercept"></script><?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Hands-on System Design with Java Spring Boot]]></title><description><![CDATA[This course provides an in-depth, hands-on journey into designing and implementing ultra-scalable task schedulers using Java Spring Boot. You will learn every core system design concept, explore diverse use cases, and gain practical experience]]></description><link>https://javatsc.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!2-je!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2c5f1ee-98fe-4d4e-a2fc-c6f53762b126_1024x1024.png</url><title>Hands-on System Design with Java Spring Boot</title><link>https://javatsc.substack.com</link></image><generator>Substack</generator><lastBuildDate>Tue, 01 Sep 2026 21:10:32 GMT</lastBuildDate><atom:link href="/__u/javatsc.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[javap]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[javatsc@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[javatsc@substack.com]]></itunes:email><itunes:name><![CDATA[System Design With Java]]></itunes:name></itunes:owner><itunes:author><![CDATA[System Design With Java]]></itunes:author><googleplay:owner><![CDATA[javatsc@substack.com]]></googleplay:owner><googleplay:email><![CDATA[javatsc@substack.com]]></googleplay:email><googleplay:author><![CDATA[System Design With Java]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Day 67: Building an SFU I — Accepting and Forwarding RTP Streams]]></title><description><![CDATA[The Junior Engineer&#8217;s Trap]]></description><link>https://javatsc.substack.com/p/day-67-building-an-sfu-i-accepting</link><guid isPermaLink="false">https://javatsc.substack.com/p/day-67-building-an-sfu-i-accepting</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Tue, 01 Sep 2026 01:45:39 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!F0sy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495e2a40-bdeb-40b2-af63-b3305abe71af_1075x625.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>The Junior Engineer&#8217;s Trap</h2><blockquote><p>A junior engineer tasked with building voice routing reaches for Pion (Go) or mediasoup (Node.js) and wires it to a Java service via gRPC. On paper, this works. In production at 50k concurrent voice participants, you hit the wall:</p><ul><li><p>mediasoup is single-threaded per worker. You spawn 32 workers. Ops screams about process management complexity.</p></li><li><p>gRPC serialization overhead on every RTP packet (arriving at 50 packets/sec per publisher) becomes your dominant CPU cost.</p></li><li><p>You have zero visibility into the JVM&#8217;s interaction with the native media layer.</p></li></ul><p>The real problem: they treated RTP forwarding as someone else&#8217;s problem. An SFU is not complicated. It is a <strong>UDP packet router with subscriber state</strong>. You can build the core in pure Java NIO in an afternoon.</p></blockquote><h2>The Failure Mode: Thread-Per-Subscriber at Scale</h2><blockquote><p>The naive implementation looks like this:</p></blockquote><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;c0c3f25f-d619-4238-a5b2-c14195d06bae&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">// DO NOT DO THIS
ExecutorService pool = Executors.newCachedThreadPool();
while (true) {
    DatagramPacket pkt = receive();
    for (Subscriber s : room.subscribers()) {
        pool.submit(() -&gt; s.send(pkt)); // new Runnable allocation per packet per subscriber
    }
}</code></pre></div><blockquote><p>At 1,000 subscribers receiving 50 RTP packets/sec from one publisher:</p><ul><li><p><strong>50,000 task submissions/sec</strong> into the thread pool</p></li><li><p>Each <code>submit()</code> allocates a <code>FutureTask</code> wrapping a lambda capturing <code>pkt</code> and <code>s</code></p></li><li><p>Eden space fills in seconds; minor GC fires every 200ms</p></li><li><p>During GC pause, the receive loop stalls &#8212; <strong>you drop RTP packets</strong></p></li><li><p>Dropped RTP = audio glitches. Users hear choppy voice.</p></li></ul><p>The second failure is <strong>copying the payload</strong>. If you call <code>pkt.getData()</code> and copy the byte array for each subscriber, you are doing O(n) heap allocations per packet. At 1,000 subscribers, that is 1,000 &#215; 1,400 bytes = 1.4MB of garbage <strong>per packet</strong>, <strong>50 times per second</strong> = <strong>70MB/sec of Eden pressure</strong>.</p></blockquote><h2>The Flux SFU Architecture</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!F0sy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495e2a40-bdeb-40b2-af63-b3305abe71af_1075x625.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!F0sy!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495e2a40-bdeb-40b2-af63-b3305abe71af_1075x625.png 424w, /__u/substackcdn.com/image/fetch/$s_!F0sy!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495e2a40-bdeb-40b2-af63-b3305abe71af_1075x625.png 848w, /__u/substackcdn.com/image/fetch/$s_!F0sy!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495e2a40-bdeb-40b2-af63-b3305abe71af_1075x625.png 1272w, /__u/substackcdn.com/image/fetch/$s_!F0sy!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495e2a40-bdeb-40b2-af63-b3305abe71af_1075x625.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!F0sy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495e2a40-bdeb-40b2-af63-b3305abe71af_1075x625.png" width="463" height="269.1860465116279" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/495e2a40-bdeb-40b2-af63-b3305abe71af_1075x625.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:625,&quot;width&quot;:1075,&quot;resizeWidth&quot;:463,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!F0sy!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495e2a40-bdeb-40b2-af63-b3305abe71af_1075x625.png 424w, /__u/substackcdn.com/image/fetch/$s_!F0sy!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495e2a40-bdeb-40b2-af63-b3305abe71af_1075x625.png 848w, /__u/substackcdn.com/image/fetch/$s_!F0sy!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495e2a40-bdeb-40b2-af63-b3305abe71af_1075x625.png 1272w, /__u/substackcdn.com/image/fetch/$s_!F0sy!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F495e2a40-bdeb-40b2-af63-b3305abe71af_1075x625.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>There are four key design decisions here.</p>
      <p>
          <a href="/__u/javatsc.substack.com/p/day-67-building-an-sfu-i-accepting">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 66: SFU Architecture: Why we need a Selective Forwarding Unit (SFU) for groups.]]></title><description><![CDATA[The &#8220;Spring Boot&#8221; Trap]]></description><link>https://javatsc.substack.com/p/day-66-sfu-architecture-why-we-need</link><guid isPermaLink="false">https://javatsc.substack.com/p/day-66-sfu-architecture-why-we-need</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Thu, 27 Aug 2026 01:45:40 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!2JPt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31c8d09f-41fc-4544-8d95-5740b5f4be4e_1175x775.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>The &#8220;Spring Boot&#8221; Trap</h2><blockquote><p>A junior engineer building group video calls sees WebRTC as a peer-to-peer technology and concludes the server&#8217;s job is minimal &#8212; just exchange SDP offers and ICE candidates over the existing WebSocket connection, then get out of the way. In a two-person call, this works perfectly. The moment a third person joins, the architecture starts showing cracks.</p><p>The naive mental model: <code>N</code> participants form a mesh. Each peer connects directly to every other peer. The server stays stateless.</p><p>In a 6-person call, that&#8217;s <code>N&#215;(N-1) = 30</code> RTCPeerConnection instances across the group. Each participant encodes their camera stream once and uploads it 5 times &#8212; one copy per remote peer. On a mobile device with a 2 Mbps uplink at 720p, you&#8217;ve already saturated the connection before encoding overhead. At 10 participants, each person is maintaining 9 simultaneous DTLS-SRTP sessions, negotiating 9 separate ICE candidate exchanges, and your signaling server is managing <code>O(N&#178;)</code> state transitions per room join or leave event.</p><p>This is the P2P Mesh failure mode. It doesn&#8217;t collapse under server load &#8212; it collapses under client load. Users on mobile drop out. Low-bandwidth users drag the entire call quality down. The &#8220;framework&#8221; hides this because WebRTC libraries abstract the peer connection count from you.</p></blockquote><h2>The Failure Modes: Mesh, then MCU</h2><blockquote><p><strong>P2P Mesh at scale:</strong> Upload bandwidth grows linearly with room size. The client, not your server, is the bottleneck. A Discord-scale voice channel with 25 participants is physically impossible over mesh &#8212; no consumer device can sustain 24 simultaneous encoded upload streams.</p><p><strong>The MCU &#8220;fix&#8221;:</strong> A Multipoint Control Unit receives all streams, decodes each one, mixes the audio and composites the video into a single output stream, then re-encodes and sends one stream to each participant. Upload problem solved. But now your server is running a real-time video encoder for every active room. At 10,000 concurrent 6-person rooms, you need GPU farms just for mixing. Latency spikes because decode &#8594; mix &#8594; encode adds 100&#8211;200ms minimum. This is how legacy enterprise conferencing (WebEx, early Zoom) was built, and it&#8217;s why it needed dedicated server infrastructure.</p></blockquote><h2>The Flux Architecture: The SFU</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!2JPt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31c8d09f-41fc-4544-8d95-5740b5f4be4e_1175x775.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!2JPt!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31c8d09f-41fc-4544-8d95-5740b5f4be4e_1175x775.png 424w, /__u/substackcdn.com/image/fetch/$s_!2JPt!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31c8d09f-41fc-4544-8d95-5740b5f4be4e_1175x775.png 848w, /__u/substackcdn.com/image/fetch/$s_!2JPt!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31c8d09f-41fc-4544-8d95-5740b5f4be4e_1175x775.png 1272w, /__u/substackcdn.com/image/fetch/$s_!2JPt!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31c8d09f-41fc-4544-8d95-5740b5f4be4e_1175x775.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!2JPt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31c8d09f-41fc-4544-8d95-5740b5f4be4e_1175x775.png" width="508" height="335.06382978723406" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/31c8d09f-41fc-4544-8d95-5740b5f4be4e_1175x775.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:775,&quot;width&quot;:1175,&quot;resizeWidth&quot;:508,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!2JPt!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31c8d09f-41fc-4544-8d95-5740b5f4be4e_1175x775.png 424w, /__u/substackcdn.com/image/fetch/$s_!2JPt!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31c8d09f-41fc-4544-8d95-5740b5f4be4e_1175x775.png 848w, /__u/substackcdn.com/image/fetch/$s_!2JPt!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31c8d09f-41fc-4544-8d95-5740b5f4be4e_1175x775.png 1272w, /__u/substackcdn.com/image/fetch/$s_!2JPt!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31c8d09f-41fc-4544-8d95-5740b5f4be4e_1175x775.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>A Selective Forwarding Unit sits between the two extremes. Each participant uploads exactly <strong>one</strong> copy of their media stream to the SFU. The SFU receives RTP packets from each publisher and <strong>forwards</strong> them &#8212; without decoding or re-encoding &#8212; to each subscriber in the room.</p>
      <p>
          <a href="/__u/javatsc.substack.com/p/day-66-sfu-architecture-why-we-need">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Week 6: Building a Resilient Scheduler (Days 26–30)]]></title><description><![CDATA[Resilient Scheduler Studio]]></description><link>https://javatsc.substack.com/p/week-6-building-a-resilient-scheduler</link><guid isPermaLink="false">https://javatsc.substack.com/p/week-6-building-a-resilient-scheduler</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Tue, 25 Aug 2026 02:30:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ho3Q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec28d8e-f083-40de-9604-b032238114b3_1125x625.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Resilient Scheduler Studio</h2><blockquote><p>This week we stop treating a scheduler like a stopwatch and start treating it like a living production system. A real scheduler does not just know <strong>when</strong> to run work. It must also know what to do when work gets stuck, when an upstream service starts behaving badly, and when the application itself is shutting down. That is the mindset behind this integrated project.</p></blockquote><h2>Agenda</h2><blockquote><p>We will build one control-room style application with five connected abilities:</p><ol><li><p>capture exhausted work in a dead-letter queue for operator review,</p></li><li><p>protect remote calls with a circuit breaker,</p></li><li><p>move execution off the request thread into worker pools,</p></li><li><p>stop runaways with timeout cancellation,</p></li><li><p>finish cleanly during shutdown instead of abandoning state.</p></li></ol><p>Think of it like an airport. The scheduler is the tower, the worker pool is the runway team, the circuit breaker is weather control, the timeout is the safety clock, and the dead-letter queue is the inspection bay for flights that could not depart safely.</p></blockquote><h2>Where it fits in a distributed scheduler</h2><blockquote><p>In a larger task scheduling platform, this module sits between task creation and task completion. Upstream systems create work through an API. The scheduler persists the task, dispatches it to async workers, watches elapsed time, and records the final outcome. If an external dependency becomes flaky, the circuit breaker stops the system from wasting threads on doomed calls. If retries still cannot recover the task, the dead-letter queue preserves the exact failure for manual analysis.</p><p>This is common in systems people already use every day: payment retries, report generation, notification delivery, and partner-data sync pipelines. The clever part is not just getting a success path working. The clever part is giving operators a clean answer when something unusual happens.</p></blockquote><h2>Component architecture</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!ho3Q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec28d8e-f083-40de-9604-b032238114b3_1125x625.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!ho3Q!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec28d8e-f083-40de-9604-b032238114b3_1125x625.png 424w, /__u/substackcdn.com/image/fetch/$s_!ho3Q!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec28d8e-f083-40de-9604-b032238114b3_1125x625.png 848w, /__u/substackcdn.com/image/fetch/$s_!ho3Q!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec28d8e-f083-40de-9604-b032238114b3_1125x625.png 1272w, /__u/substackcdn.com/image/fetch/$s_!ho3Q!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec28d8e-f083-40de-9604-b032238114b3_1125x625.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!ho3Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec28d8e-f083-40de-9604-b032238114b3_1125x625.png" width="532" height="295.55555555555554" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aec28d8e-f083-40de-9604-b032238114b3_1125x625.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:625,&quot;width&quot;:1125,&quot;resizeWidth&quot;:532,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!ho3Q!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec28d8e-f083-40de-9604-b032238114b3_1125x625.png 424w, /__u/substackcdn.com/image/fetch/$s_!ho3Q!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec28d8e-f083-40de-9604-b032238114b3_1125x625.png 848w, /__u/substackcdn.com/image/fetch/$s_!ho3Q!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec28d8e-f083-40de-9604-b032238114b3_1125x625.png 1272w, /__u/substackcdn.com/image/fetch/$s_!ho3Q!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec28d8e-f083-40de-9604-b032238114b3_1125x625.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/javatsc.substack.com/p/week-6-building-a-resilient-scheduler">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 65: NAT Traversal: Setting up a STUN server (coturn) and testing connectivity]]></title><description><![CDATA[What You Will Learn]]></description><link>https://javatsc.substack.com/p/day-65-nat-traversal-setting-up-a</link><guid isPermaLink="false">https://javatsc.substack.com/p/day-65-nat-traversal-setting-up-a</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Sun, 23 Aug 2026 01:45:36 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Fv0E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f37db2a-4ef4-4103-bdcd-96c21a4bd4a8_1100x700.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What You Will Learn</h2><blockquote><p>By the end of this lesson you will understand exactly what happens between the moment a user clicks &#8220;Join Voice&#8221; and the moment audio starts flowing. You will build a real STUN server in pure Java &#8212; not a wrapper around coturn, not a config file &#8212; an actual RFC 5389 binary protocol parser that handles XOR address encoding, lock-free counters, and zero-allocation UDP I/O. This is the foundation every voice calling system in the world is built on.</p></blockquote><h2>The Junior Engineer&#8217;s Trap</h2><blockquote><p>A junior engineer hears &#8220;STUN server&#8221; and reaches for a library. They find coturn, run <code>apt install coturn</code>, paste a config file into <code>/etc/turnserver.conf</code>, and declare the problem solved. The lesson ends before it begins.</p><p>The problem is that coturn is a black box. When your voice calls start failing under load because a NAT mapping expired mid-session, or when ICE candidates arrive with the wrong reflexive address because the STUN response was malformed, you have nowhere to look. You cannot debug a binary you did not write.</p><p>More to the point: if you are building a Discord-scale system, you will eventually run your own STUN infrastructure. At 100 million concurrent users, even a 0.1% ICE failure rate means 100,000 broken calls in the same instant. You need to own this protocol down to the byte.</p></blockquote><h2>The Failure Mode: Thread-Per-Datagram</h2><blockquote><p>The naive implementation looks like this. Open a <code>DatagramSocket</code>. Call <code>receive()</code> in a loop. Spawn a new thread for each packet. Build a response. Send it. This works for ten users in a demo.</p><p>At 50,000 binding requests per second &#8212; a modest voice call storm during a large event &#8212; you have 50,000 <code>DatagramPacket</code> allocations per second landing in Eden space. Each <code>DatagramPacket</code> wraps a <code>byte[]</code>. Fifty thousand arrays per second, each between 20 and 576 bytes, fills Eden in milliseconds. Minor GC fires every 200ms. Each minor GC pauses all threads for 5 to 15ms. During that pause, UDP datagrams queue inside the kernel socket buffer. When GC finishes, you process a burst. Latency spikes. ICE checks time out. Calls drop.</p><p>The OS makes it worse. UDP socket receive buffers default to 208 KB on Linux. At 50,000 datagrams per second, you overflow that buffer in under 5ms during a single GC pause. The kernel silently drops the overflow. Your ICE negotiation never completes, and you get no error &#8212; just silence.</p><p>The thread model fails independently of the GC problem. Each thread context-switch costs between 1 and 5 microseconds. With 1,000 threads live, you are burning CPU cycles on the OS scheduler before you parse a single byte of STUN payload.</p></blockquote><h2>The Flux Architecture: Single-Threaded Selector Loop</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!Fv0E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f37db2a-4ef4-4103-bdcd-96c21a4bd4a8_1100x700.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!Fv0E!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f37db2a-4ef4-4103-bdcd-96c21a4bd4a8_1100x700.png 424w, /__u/substackcdn.com/image/fetch/$s_!Fv0E!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f37db2a-4ef4-4103-bdcd-96c21a4bd4a8_1100x700.png 848w, /__u/substackcdn.com/image/fetch/$s_!Fv0E!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f37db2a-4ef4-4103-bdcd-96c21a4bd4a8_1100x700.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Fv0E!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f37db2a-4ef4-4103-bdcd-96c21a4bd4a8_1100x700.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!Fv0E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f37db2a-4ef4-4103-bdcd-96c21a4bd4a8_1100x700.png" width="518" height="329.6363636363636" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9f37db2a-4ef4-4103-bdcd-96c21a4bd4a8_1100x700.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:700,&quot;width&quot;:1100,&quot;resizeWidth&quot;:518,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!Fv0E!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f37db2a-4ef4-4103-bdcd-96c21a4bd4a8_1100x700.png 424w, /__u/substackcdn.com/image/fetch/$s_!Fv0E!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f37db2a-4ef4-4103-bdcd-96c21a4bd4a8_1100x700.png 848w, /__u/substackcdn.com/image/fetch/$s_!Fv0E!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f37db2a-4ef4-4103-bdcd-96c21a4bd4a8_1100x700.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Fv0E!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f37db2a-4ef4-4103-bdcd-96c21a4bd4a8_1100x700.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>STUN over UDP maps perfectly to the Reactor pattern. One thread. One <code>DatagramChannel</code> in non-blocking mode. One <code>Selector</code>. No allocation per datagram &#8212; we reuse a single <code>ByteBuffer</code> for receives and a separate <code>ByteBuffer</code> for responses.</p><pre><code><code>DatagramChannel (non-blocking)
    &#8594; Selector.select()
    &#8594; recvBuf.clear(); channel.receive(recvBuf)
    &#8594; recvBuf.flip(); StunMessage.parse()
    &#8594; StunResponseBuilder.build(msg, sendBuf)
    &#8594; sendBuf.flip(); channel.send(sendBuf, sender)
    &#8594; back to select()</code></code></pre><p>The STUN RFC 5389 binary format is simple enough to parse entirely with <code>ByteBuffer.get()</code> calls and zero heap allocation beyond the <code>StunMessage</code> record. After escape analysis the JIT will stack-allocate that record in the hot path. We use pre-allocated direct <code>ByteBuffer</code> instances for both read and write, so UDP payloads never touch the heap at all.</p><p>The dashboard runs on a Virtual Thread &#8212; blocking HTTP is perfectly acceptable there. The critical path (the selector loop) stays single-threaded and allocation-free.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!LOY_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8130e02f-5016-4bbb-8bc5-80d35eb383ad_1175x750.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!LOY_!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8130e02f-5016-4bbb-8bc5-80d35eb383ad_1175x750.png 424w, /__u/substackcdn.com/image/fetch/$s_!LOY_!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8130e02f-5016-4bbb-8bc5-80d35eb383ad_1175x750.png 848w, /__u/substackcdn.com/image/fetch/$s_!LOY_!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8130e02f-5016-4bbb-8bc5-80d35eb383ad_1175x750.png 1272w, /__u/substackcdn.com/image/fetch/$s_!LOY_!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8130e02f-5016-4bbb-8bc5-80d35eb383ad_1175x750.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!LOY_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8130e02f-5016-4bbb-8bc5-80d35eb383ad_1175x750.png" width="518" height="330.63829787234044" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8130e02f-5016-4bbb-8bc5-80d35eb383ad_1175x750.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:750,&quot;width&quot;:1175,&quot;resizeWidth&quot;:518,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!LOY_!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8130e02f-5016-4bbb-8bc5-80d35eb383ad_1175x750.png 424w, /__u/substackcdn.com/image/fetch/$s_!LOY_!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8130e02f-5016-4bbb-8bc5-80d35eb383ad_1175x750.png 848w, /__u/substackcdn.com/image/fetch/$s_!LOY_!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8130e02f-5016-4bbb-8bc5-80d35eb383ad_1175x750.png 1272w, /__u/substackcdn.com/image/fetch/$s_!LOY_!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8130e02f-5016-4bbb-8bc5-80d35eb383ad_1175x750.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Implementation Deep Dive</h2><h3>GitHub Link :</h3><p><a href="https://github.com/sysdr/discord-flux-p/tree/main/day65/flux-stun">https://github.com/sysdr/discord-flux-p/tree/main/day65/flux-stun</a></p><h3>The STUN Message Format (RFC 5389, Section 6)</h3><p>Every STUN message starts with a 20-byte header structured exactly like this:</p><pre><code><code> 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0 0|     STUN Message Type     |         Message Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Magic Cookie (0x2112A442)                   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                     Transaction ID (96 bits)                  |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</code></code></pre><p>The <strong>Magic Cookie</strong> (<code>0x2112A442</code>) is your first validation gate. If it is missing, drop the datagram without sending a response. No point processing garbage.</p><p>The top two bits of the message type field must always be zero. If they are not, the packet is not STUN.</p><p>Message type <code>0x0001</code> = Binding Request. You respond with <code>0x0101</code> = Binding Success Response.</p><p>The 12-byte Transaction ID is how the client matches your response to the request it sent. You copy it verbatim into the response header.</p><h3>XOR-MAPPED-ADDRESS Construction</h3><p>The reflexive address &#8212; the client&#8217;s public IP as seen by your server &#8212; must be XOR&#8217;d against the magic cookie before you send it back. This is not optional. RFC 5389 requires it specifically to defeat Application Layer Gateways: NAT devices that scan UDP payloads looking for IP addresses and rewrite them. XOR encoding makes the address unrecognizable to those devices.</p><p>For an IPv4 client the math is:</p><pre><code><code>XOR'd port = client_port    XOR (0x2112A442 &gt;&gt; 16)   // XOR against high 16 bits of magic cookie
XOR'd IP   = client_ip_int  XOR 0x2112A442            // XOR against full magic cookie</code></code></pre><p>The ICE agent on the other end knows the magic cookie and reverses the XOR to recover the real address.</p><h3>The Zero-Allocation Pattern</h3><p>Pre-allocate both buffers once at startup before the selector loop begins:</p><pre><code><code>ByteBuffer recvBuf = ByteBuffer.allocateDirect(576); // max STUN payload
ByteBuffer sendBuf = ByteBuffer.allocateDirect(576);</code></code></pre><p><code>allocateDirect</code> puts these buffers in native memory &#8212; completely off the Java heap, invisible to the garbage collector. Inside the selector loop:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;b1ac11a3-20f7-4818-9ee5-c5697b161432&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">recvBuf.clear();                                      // reset position/limit, no allocation
InetSocketAddress sender = (InetSocketAddress) channel.receive(recvBuf);
recvBuf.flip();                                       // prepare for reading
StunMessage msg = StunMessage.parse(recvBuf, sender); // reads directly from buffer</code></pre></div><p>Nothing in this path creates a new object on the heap. The <code>StunMessage</code> record is the only candidate, and after a few thousand iterations the JIT&#8217;s escape analysis confirms it never leaves the method &#8212; it gets stack-allocated and costs nothing.</p><h3>VarHandle for Lock-Free Stats</h3><p>Instead of <code>AtomicLong</code>, which boxes every access through an object header, we use <code>VarHandle</code> on a <code>long[]</code>:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;f3dab8ff-9434-4865-8ff4-db07ec46819e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">private final long[] counters = new long[4]; // requests, responses, errors, invalid
private static final VarHandle VH =
    MethodHandles.arrayElementVarHandle(long[].class);

// In the hot path:
VH.getAndAdd(counters, IDX_REQUESTS, 1L);</code></pre></div><p>This is a single CPU instruction (lock xadd on x86) with no object allocation and no lock overhead.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!XErV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F026eb735-d5c9-46e6-a675-504e35ffe5d9_1150x775.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!XErV!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F026eb735-d5c9-46e6-a675-504e35ffe5d9_1150x775.png 424w, /__u/substackcdn.com/image/fetch/$s_!XErV!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F026eb735-d5c9-46e6-a675-504e35ffe5d9_1150x775.png 848w, /__u/substackcdn.com/image/fetch/$s_!XErV!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F026eb735-d5c9-46e6-a675-504e35ffe5d9_1150x775.png 1272w, /__u/substackcdn.com/image/fetch/$s_!XErV!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F026eb735-d5c9-46e6-a675-504e35ffe5d9_1150x775.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!XErV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F026eb735-d5c9-46e6-a675-504e35ffe5d9_1150x775.png" width="500" height="336.95652173913044" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/026eb735-d5c9-46e6-a675-504e35ffe5d9_1150x775.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:775,&quot;width&quot;:1150,&quot;resizeWidth&quot;:500,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!XErV!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F026eb735-d5c9-46e6-a675-504e35ffe5d9_1150x775.png 424w, /__u/substackcdn.com/image/fetch/$s_!XErV!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F026eb735-d5c9-46e6-a675-504e35ffe5d9_1150x775.png 848w, /__u/substackcdn.com/image/fetch/$s_!XErV!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F026eb735-d5c9-46e6-a675-504e35ffe5d9_1150x775.png 1272w, /__u/substackcdn.com/image/fetch/$s_!XErV!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F026eb735-d5c9-46e6-a675-504e35ffe5d9_1150x775.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Working Demo Link :</h3><div id="youtube2-ITjEIPskZvo" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;ITjEIPskZvo&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/ITjEIPskZvo?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h2>Production Readiness</h2><p>These are the numbers you instrument and alert on before you ship a STUN server:</p><p>Metric How to Measure Alert Threshold Binding requests per second JMX / Prometheus counter Alert above 80K/sec per instance UDP receive buffer drops <code>netstat -su</code> or <code>/proc/net/udp</code> Any non-zero value is a capacity event GC allocation rate on selector thread VisualVM Profiler Under 1 MB/sec &#8212; should be near zero STUN error rate Internal <code>StunStats</code> counter Above 0.1% triggers investigation Response latency P99 Histogram in dashboard Under 5ms</p><p>On Linux, tune the kernel socket buffers before starting the server:</p><pre><code><code>sysctl -w net.core.rmem_max=26214400
sysctl -w net.core.rmem_default=26214400</code></code></pre><p>25 MB of receive buffer means you can absorb roughly 40,000 full-size STUN datagrams during a 5ms GC pause without dropping a single packet.</p><h2>Build, Run, and Verify</h2><h3>Prerequisites</h3><p>Make sure these are installed before you start:</p><ul><li><p>JDK 21 or later &#8212; run <code>java -version</code> to confirm</p></li><li><p>Maven 3.9 or later &#8212; run <code>mvn -version</code> to confirm</p></li><li><p>Python 3 (for the verify script&#8217;s packet parsing step)</p></li><li><p>VisualVM &#8212; download from visualvm.github.io, used to confirm zero allocation on the selector thread</p></li><li><p><code>netcat</code> (<code>nc</code>) &#8212; optional, for raw UDP testing</p></li></ul><h3>Step 1 &#8212; Generate the Workspace</h3><h3>Build and Start</h3><pre><code><code>./start.sh</code></code></pre><p>This compiles the project with Maven and starts two things: the STUN server on UDP port 3478, and the dashboard web server on TCP port 9090.</p><p>Expected output:</p><pre><code><code>Building flux-stun...
STUN  server: UDP :3478
Dashboard:    http://localhost:9090
[stun-selector] INFO: STUN server listening on UDP :3478</code></code></pre><h3>Step 2 &#8212; Open the Dashboard</h3><p>Navigate to http://localhost:9090 in your browser.</p><p>You should see the live stats panel with counters for total requests, responses sent, invalid packets, unique source IPs, and requests per second. All counters start at zero.</p><h3>Step 3 &#8212; Run the Unit Tests</h3><p>Open a second terminal in the <code>flux-stun</code> directory and run:</p><pre><code><code>mvn test</code></code></pre><p>All three test classes run: <code>StunMessageTest</code>, <code>StunResponseBuilderTest</code>, and <code>StunIntegrationTest</code>. The integration test starts its own STUN server instance on port 13478 (a non-privileged test port), fires single and concurrent requests against it, and verifies the response counters match exactly.</p><p>Expected output:</p><pre><code><code>[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0 -- StunMessageTest
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 -- StunResponseBuilderTest
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 -- StunIntegrationTest
[INFO] BUILD SUCCESS</code></code></pre><h3>Step 4 &#8212; Run the Demo</h3><pre><code><code>./demo.sh</code></code></pre><p>This fires 1,000 STUN Binding Requests from virtual threads against your running server, then uses a Python script to send one additional request manually and parse the raw XOR-MAPPED-ADDRESS attribute from the binary response.</p><p>You will see output like:</p><pre><code><code>=== Flux STUN Demo: NAT Traversal ===
Firing 1000 STUN Binding Requests via Virtual Threads...
Storm sent. Check dashboard: http://localhost:9090

Sending a single test request with netcat (hex):
  Response type: 0x0101 (Binding Success)
  Response length: 40 bytes
  Hex: 0101001421...</code></code></pre><p>Switch to the dashboard tab and observe the counters update.</p><h3>Step 5 &#8212; Verify Responses and XOR Decoding</h3><pre><code><code>./verify.sh</code></code></pre><p>This script does four things in order:</p><ol><li><p>Confirms the server process is running via the PID file</p></li><li><p>Checks that UDP port 3478 is listed as bound using <code>ss -ulnp</code></p></li><li><p>Sends a STUN Binding Request with a known transaction ID and parses the binary response, printing the decoded XOR-MAPPED-ADDRESS</p></li><li><p>Hits the dashboard API endpoint and prints the current JSON stats</p></li></ol><p>Expected output:</p><pre><code><code>[OK] STUN server running (PID 12345)
[OK] UDP :3478 is open
[OK] Binding Response received
     Type:           0x0101
     Magic Cookie:   0x2112A442
     Transaction ID: 000102030405060708090a0b
[OK] XOR-MAPPED-ADDRESS: 127.0.0.1:XXXXX
     (This is your reflexive/public address as seen by the STUN server)
[OK] Dashboard API responding (HTTP 200)
     Stats: {"requests":1002,"responses":1002,"errors":0,"invalid":0,"uniqueIps":1,"reqPerSec":"..."}
[OK] All verification checks passed.</code></code></pre><p>The reflexive address showing <code>127.0.0.1</code> is correct here because the verify script runs on localhost. In a real deployment, a client behind a home router would see their public IP.</p><h3>Stopping and Cleaning Up</h3><pre><code><code># Stop the running server process only:
./stop.sh

# Remove build artifacts (does not kill the server):
./cleanup.sh</code></code></pre><h2>Homework Challenges</h2><p><strong>Beginner</strong> &#8212; Add a <code>SOFTWARE</code> attribute (attribute type <code>0x8022</code>) to every Binding Response. The value is a UTF-8 string containing your server name and version, for example <code>"Flux-STUN/1.0"</code>. Pad the attribute value to a 4-byte boundary as required by RFC 5389. Verify the attribute appears in the response using <code>verify.sh</code> and the hex dump it prints. (The existing <code>StunResponseBuilder</code> already includes this &#8212; read through the implementation and make sure you understand each byte it writes.)</p><p><strong>Intermediate</strong> &#8212; Implement <code>MESSAGE-INTEGRITY</code> validation (RFC 5389, Section 15.4). This is HMAC-SHA1 over the message content using a shared password. Add a <code>StunCredential</code> record to carry the username and password. Add a validation step in <code>StunServer.handleDatagrams()</code> that checks the HMAC before building a response. Update <code>StunLoadClient</code> to include the <code>USERNAME</code> and <code>MESSAGE-INTEGRITY</code> attributes in outgoing requests. Write a test that confirms a request with a wrong password gets an error response (<code>0x0111</code>) with an <code>ERROR-CODE</code> attribute.</p><p><strong>Expert</strong> &#8212; Add the <code>FINGERPRINT</code> attribute (RFC 5389, Section 15.5). This is a CRC-32 checksum of the entire message XOR&#8217;d with <code>0x5354554e</code>. Run <code>./demo.sh</code> firing 50,000 requests and use <code>/proc/net/udp</code> or <code>netstat -su</code> to count UDP receive buffer drops. Tune <code>SO_RCVBUF</code> from the default up to 25 MB in <code>StunServer.java</code> and measure the minimum buffer size that produces zero drops on your hardware at that load.</p><div><hr></div><p><em>Next: Day 66 &#8212; TURN Relay: When STUN Is Not Enough</em></p>]]></content:encoded></item><item><title><![CDATA[Week 5: Task Lifecycle & Recovery (Days 21–25)]]></title><description><![CDATA[Why This Matters]]></description><link>https://javatsc.substack.com/p/week-5-task-lifecycle-and-recovery</link><guid isPermaLink="false">https://javatsc.substack.com/p/week-5-task-lifecycle-and-recovery</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Thu, 20 Aug 2026 02:30:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!VLby!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9049a75-af56-4207-95a0-301765814835_1125x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Why This Matters</h2><blockquote><p>Gmail still delivers your mail when a SMTP relay blips. Stripe still settles payments after a network timeout. Your bank&#8217;s nocturnal batch does not &#8220;forget&#8221; mid-run because one pod restarted. They share a boring superpower: every attempt is <strong>recorded</strong>, every status change is <strong>legal</strong>, every failure is <strong>classified</strong>, and retries are <strong>bounded with backoff</strong>.</p><p>A scheduler without a lifecycle is a stopwatch with amnesia. At scale, amnesia is an outage you cannot explain.</p></blockquote><h2>Agenda</h2><blockquote><ol><li><p>Execution ledger (who ran what, when, with what outcome)</p></li><li><p>Status state machine (illegal transitions rejected)</p></li><li><p>Error capture (message + stack persisted)</p></li><li><p>Durable exponential backoff (<code>RETRYING</code> + <code>nextRetryAt</code>)</p></li><li><p>Spring Retry for in-process transient slices</p></li><li><p>Dead letter when hope is gone</p></li><li><p>Build, test, demo</p></li></ol></blockquote><h2>Core Concepts</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!VLby!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9049a75-af56-4207-95a0-301765814835_1125x512.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!VLby!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9049a75-af56-4207-95a0-301765814835_1125x512.png 424w, /__u/substackcdn.com/image/fetch/$s_!VLby!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9049a75-af56-4207-95a0-301765814835_1125x512.png 848w, /__u/substackcdn.com/image/fetch/$s_!VLby!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9049a75-af56-4207-95a0-301765814835_1125x512.png 1272w, /__u/substackcdn.com/image/fetch/$s_!VLby!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9049a75-af56-4207-95a0-301765814835_1125x512.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!VLby!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9049a75-af56-4207-95a0-301765814835_1125x512.png" width="532" height="242.11911111111112" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c9049a75-af56-4207-95a0-301765814835_1125x512.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:512,&quot;width&quot;:1125,&quot;resizeWidth&quot;:532,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!VLby!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9049a75-af56-4207-95a0-301765814835_1125x512.png 424w, /__u/substackcdn.com/image/fetch/$s_!VLby!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9049a75-af56-4207-95a0-301765814835_1125x512.png 848w, /__u/substackcdn.com/image/fetch/$s_!VLby!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9049a75-af56-4207-95a0-301765814835_1125x512.png 1272w, /__u/substackcdn.com/image/fetch/$s_!VLby!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9049a75-af56-4207-95a0-301765814835_1125x512.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>1. Execution Ledger</h3><p>Before you optimize throughput, you need a <strong>flight recorder</strong>. Each attempt gets a UUID <code>executionId</code>, start/end timestamps, duration, node id, and either an outcome or an error+stack. Netflix-style ops dashboards are useless without this row-level truth.</p><p><strong>Insight:</strong> Metrics tell you <em>rates</em>; the ledger tells you <em>stories</em>. When a VP asks &#8220;what happened to job X at 02:14?&#8221;, you open one row&#8212;not a haystack of logs.</p>
      <p>
          <a href="/__u/javatsc.substack.com/p/week-5-task-lifecycle-and-recovery">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 64: The Offer/Answer Dance: Exchanging JSON-RPC SDP payloads over WebSockets]]></title><description><![CDATA[The Spring Boot Trap]]></description><link>https://javatsc.substack.com/p/day-64-the-offeranswer-dance-exchanging</link><guid isPermaLink="false">https://javatsc.substack.com/p/day-64-the-offeranswer-dance-exchanging</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Wed, 19 Aug 2026 08:12:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!JW60!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08393dc6-9419-4f01-83ea-eae865ba9e2e_1125x700.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>The Spring Boot Trap</h2><p>A junior engineer discovers <code>spring-webrtc</code> or reaches for a JSON library to relay SDP blobs. The code looks like this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;ae578854-5fdb-449b-a71f-d3fc3bd2b677&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">@MessageMapping("/sdp-offer")
public void handleOffer(String sdpJson, SimpMessageHeaderAccessor headers) {
    String sessionId = headers.getSessionId();
    sdpStore.put(sessionId, sdpJson);
    messagingTemplate.convertAndSendToUser(targetUser, "/queue/sdp", sdpJson);
}</code></pre></div><p>At 10 users in a demo this is fine. At 10,000 concurrent voice calls, you have a problem you cannot see until production explodes.</p><p>Spring&#8217;s <code>SimpMessageHeaderAccessor</code> wraps every message in a <code>Map&lt;String, Object&gt;</code> of header copies. Each SDP blob is 2&#8211;4 KB of ASCII. Each JSON serialization produces intermediate <code>String</code> and <code>byte[]</code> objects. GC pressure begins to spike before you hit 500 concurrent sessions. More critically: the session correlation model (<code>sessionId &#8594; targetId</code>) lives in a <code>HashMap</code> behind a <code>@Service</code> singleton. The first time two threads race on a state transition &#8212; offer arriving while an answer is already in flight &#8212; you get a corrupted session with no error, just a silent WebRTC failure on the client.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!JW60!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08393dc6-9419-4f01-83ea-eae865ba9e2e_1125x700.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!JW60!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08393dc6-9419-4f01-83ea-eae865ba9e2e_1125x700.png 424w, /__u/substackcdn.com/image/fetch/$s_!JW60!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08393dc6-9419-4f01-83ea-eae865ba9e2e_1125x700.png 848w, /__u/substackcdn.com/image/fetch/$s_!JW60!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08393dc6-9419-4f01-83ea-eae865ba9e2e_1125x700.png 1272w, /__u/substackcdn.com/image/fetch/$s_!JW60!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08393dc6-9419-4f01-83ea-eae865ba9e2e_1125x700.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!JW60!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08393dc6-9419-4f01-83ea-eae865ba9e2e_1125x700.png" width="512" height="318.5777777777778" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/08393dc6-9419-4f01-83ea-eae865ba9e2e_1125x700.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:700,&quot;width&quot;:1125,&quot;resizeWidth&quot;:512,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!JW60!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08393dc6-9419-4f01-83ea-eae865ba9e2e_1125x700.png 424w, /__u/substackcdn.com/image/fetch/$s_!JW60!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08393dc6-9419-4f01-83ea-eae865ba9e2e_1125x700.png 848w, /__u/substackcdn.com/image/fetch/$s_!JW60!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08393dc6-9419-4f01-83ea-eae865ba9e2e_1125x700.png 1272w, /__u/substackcdn.com/image/fetch/$s_!JW60!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08393dc6-9419-4f01-83ea-eae865ba9e2e_1125x700.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>The Failure Mode</h2><p>SDP state is a two-party handshake with strict ordering:</p><pre><code><code>Caller &#8594; OFFER &#8594; Server &#8594; forward to Callee
Callee &#8594; ANSWER &#8594; Server &#8594; forward to Caller
Both   &#8594; ICE CANDIDATES (trickle) &#8594; Server &#8594; cross-forward</code></code></pre><p>Three things break at scale with naive implementations:</p><p><strong>1. String Interning and Heap Retention</strong></p><p>SDP contains repeated attribute prefixes (<code>a=</code>, <code>m=</code>, <code>c=</code>). If you parse into <code>Map&lt;String, String&gt;</code> and retain these maps per session, the String pool bloats. With 1 million sessions at 3 KB each, retained heap from SDP strings alone exceeds 3 GB. The JVM&#8217;s G1 collector begins spending 40%+ of wall time reclaiming this.</p><p><strong>2. Unsynchronized State Transitions</strong></p><p>The session lifecycle is: <code>IDLE &#8594; OFFERING &#8594; ANSWERING &#8594; ESTABLISHED</code>. If a <code>ConcurrentHashMap.put()</code> isn&#8217;t paired with a CAS on the state field, two simultaneous answers for the same session both &#8220;succeed&#8221; and one is silently dropped.</p><p><strong>3. Trickle ICE Fan-Out</strong></p><p>After SDP exchange, each peer sends 3&#8211;10 ICE candidates. These are small messages but they arrive in a burst. A thread-per-connection model spawns hundreds of threads just for ICE candidate forwarding. Under Virtual Threads this is invisible, but if you&#8217;re on platform threads (the Spring default until explicitly configured otherwise), you hit OS thread limits fast.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!Iggv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb38e65-331f-40c4-adf0-7d44ef0799c9_1187x812.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!Iggv!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb38e65-331f-40c4-adf0-7d44ef0799c9_1187x812.png 424w, /__u/substackcdn.com/image/fetch/$s_!Iggv!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb38e65-331f-40c4-adf0-7d44ef0799c9_1187x812.png 848w, /__u/substackcdn.com/image/fetch/$s_!Iggv!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb38e65-331f-40c4-adf0-7d44ef0799c9_1187x812.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Iggv!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb38e65-331f-40c4-adf0-7d44ef0799c9_1187x812.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!Iggv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb38e65-331f-40c4-adf0-7d44ef0799c9_1187x812.png" width="502" height="343.40690817186186" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5fb38e65-331f-40c4-adf0-7d44ef0799c9_1187x812.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:812,&quot;width&quot;:1187,&quot;resizeWidth&quot;:502,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!Iggv!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb38e65-331f-40c4-adf0-7d44ef0799c9_1187x812.png 424w, /__u/substackcdn.com/image/fetch/$s_!Iggv!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb38e65-331f-40c4-adf0-7d44ef0799c9_1187x812.png 848w, /__u/substackcdn.com/image/fetch/$s_!Iggv!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb38e65-331f-40c4-adf0-7d44ef0799c9_1187x812.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Iggv!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb38e65-331f-40c4-adf0-7d44ef0799c9_1187x812.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>The Flux Architecture</h2><p>The Flux SDP Exchange system has three components.</p><p><strong>SdpSession &#8212; Sealed State Machine</strong></p><p>A <code>sealed interface</code> with <code>record</code> variants for each lifecycle state. State transitions use <code>VarHandle</code> CAS to prevent races without <code>synchronized</code> blocks.</p><p>No inheritance, no nullable fields, no <code>instanceof</code> chains. Pattern matching in switch expressions handles dispatch cleanly.</p><p><strong>SdpParser &#8212; Zero-Copy Field Extraction</strong></p><p>Rather than parsing SDP into a full object graph, we scan the raw bytes and extract only the fields we need: <code>o=</code> (origin), <code>a=fingerprint</code>, <code>a=ice-ufrag</code>, <code>a=ice-pwd</code>, and <code>m=</code> lines. We read from a <code>ByteBuffer</code> line by line using index arithmetic, never constructing intermediate substrings for lines we discard.</p><p><strong>SessionStore &#8212; Lock-Free CAS Transitions</strong></p><p><code>ConcurrentHashMap&lt;String, SdpSession&gt;</code> with <code>VarHandle</code>-based compare-and-swap for state transitions. The transition <code>OFFERING &#8594; ANSWERING</code> is only applied if the current state is <code>Offering</code>, preventing double-answer races.</p><h2>Implementation Deep Dive</h2><h3>GitHub LinK :</h3><p><a href="https://github.com/sysdr/discord-flux-p/tree/main/day64/flux-day64">https://github.com/sysdr/discord-flux-p/tree/main/day64/flux-day64</a></p><h3>Selective Field Extraction from SDP</h3><p>SDP is line-delimited. Each line starts with a single letter and <code>=</code>. We only care about a handful of them. The parser reads raw bytes from the WebSocket payload buffer:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;10d7cc22-2d4b-4af2-87e7-00316cc09a0a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">record ParsedSdp(String iceUfrag, String icePwd, String fingerprint,
                 String origin, List&lt;String&gt; mediaLines) {

    static ParsedSdp parse(String raw) {
        String iceUfrag = null, icePwd = null, fingerprint = null, origin = null;
        var mediaLines = new ArrayList&lt;String&gt;();
        for (String line : raw.split("\r?\n")) {
            if (line.startsWith("a=ice-ufrag:"))      iceUfrag    = line.substring(12);
            else if (line.startsWith("a=ice-pwd:"))   icePwd      = line.substring(10);
            else if (line.startsWith("a=fingerprint:")) fingerprint = line.substring(14);
            else if (line.startsWith("o="))            origin      = line.substring(2);
            else if (line.startsWith("m="))            mediaLines.add(line.substring(2));
        }
        return new ParsedSdp(iceUfrag, icePwd, fingerprint, origin,
                             Collections.unmodifiableList(mediaLines));
    }
}</code></pre></div><p>This allocates one <code>ParsedSdp</code> record per session instead of a full <code>Map&lt;String, String&gt;</code> with dozens of entries. Memory footprint drops by roughly 70% versus a generic SDP object model.</p><h3>VarHandle CAS for State Transitions</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;0f467fc1-aa48-461f-b514-0933fa200fbb&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">private static final VarHandle SESSION;
static {
    try {
        SESSION = MethodHandles.lookup()
            .findVarHandle(SdpExchangeHandler.class, "session", SdpSession.class);
    } catch (Exception e) { throw new ExceptionInInitializerError(e); }
}

// Atomic transition: IDLE &#8594; OFFERING
boolean registerOffer(ParsedSdp offer, String callerId) {
    var expected = new SdpSession.Idle(callId);
    var next = new SdpSession.Offering(callId, callerId, offer, System.currentTimeMillis());
    return SESSION.compareAndSet(this, expected, next);
}</code></pre></div><p>If two callers race to set an offer for the same <code>callId</code>, exactly one wins the CAS. The loser gets <code>false</code> and can signal an error immediately instead of silently overwriting.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!sVAH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f4c1185-53b6-4543-97ea-ad4544f8c92a_1200x700.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!sVAH!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f4c1185-53b6-4543-97ea-ad4544f8c92a_1200x700.png 424w, /__u/substackcdn.com/image/fetch/$s_!sVAH!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f4c1185-53b6-4543-97ea-ad4544f8c92a_1200x700.png 848w, /__u/substackcdn.com/image/fetch/$s_!sVAH!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f4c1185-53b6-4543-97ea-ad4544f8c92a_1200x700.png 1272w, /__u/substackcdn.com/image/fetch/$s_!sVAH!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f4c1185-53b6-4543-97ea-ad4544f8c92a_1200x700.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!sVAH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f4c1185-53b6-4543-97ea-ad4544f8c92a_1200x700.png" width="520" height="303.3333333333333" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4f4c1185-53b6-4543-97ea-ad4544f8c92a_1200x700.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:700,&quot;width&quot;:1200,&quot;resizeWidth&quot;:520,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!sVAH!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f4c1185-53b6-4543-97ea-ad4544f8c92a_1200x700.png 424w, /__u/substackcdn.com/image/fetch/$s_!sVAH!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f4c1185-53b6-4543-97ea-ad4544f8c92a_1200x700.png 848w, /__u/substackcdn.com/image/fetch/$s_!sVAH!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f4c1185-53b6-4543-97ea-ad4544f8c92a_1200x700.png 1272w, /__u/substackcdn.com/image/fetch/$s_!sVAH!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f4c1185-53b6-4543-97ea-ad4544f8c92a_1200x700.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Virtual Thread Per Connection</h3><p>The WebSocket server dispatches each connection to a Virtual Thread. ICE candidates arrive as additional messages on the same connection. Because Virtual Threads are cheap (~1 KB stack vs ~512 KB for platform threads), a burst of 10,000 trickle ICE messages spawns 10,000 Virtual Threads without exhausting the OS.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;426ea30d-6e39-4d8e-a3e9-e46fde988d74&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">var executor = Executors.newVirtualThreadPerTaskExecutor();
serverSocket.accept(null, new CompletionHandler&lt;&gt;() {
    public void completed(AsynchronousSocketChannel ch, Void a) {
        executor.submit(() -&gt; handleConnection(ch));
        serverSocket.accept(null, this); // re-arm
    }
});</code></pre></div><h3>Working Demo Link :</h3><div id="youtube2-n4xNpCbhCP0" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;n4xNpCbhCP0&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/n4xNpCbhCP0?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h2>Production Readiness</h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!-FJL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134376ae-0a7f-4789-9f51-a935f6cb2a8a_770x307.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!-FJL!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134376ae-0a7f-4789-9f51-a935f6cb2a8a_770x307.png 424w, /__u/substackcdn.com/image/fetch/$s_!-FJL!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134376ae-0a7f-4789-9f51-a935f6cb2a8a_770x307.png 848w, /__u/substackcdn.com/image/fetch/$s_!-FJL!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134376ae-0a7f-4789-9f51-a935f6cb2a8a_770x307.png 1272w, /__u/substackcdn.com/image/fetch/$s_!-FJL!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134376ae-0a7f-4789-9f51-a935f6cb2a8a_770x307.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!-FJL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134376ae-0a7f-4789-9f51-a935f6cb2a8a_770x307.png" width="514" height="204.93246753246754" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/134376ae-0a7f-4789-9f51-a935f6cb2a8a_770x307.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:307,&quot;width&quot;:770,&quot;resizeWidth&quot;:514,&quot;bytes&quot;:50509,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://javatsc.substack.com/i/208932678?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134376ae-0a7f-4789-9f51-a935f6cb2a8a_770x307.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!-FJL!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134376ae-0a7f-4789-9f51-a935f6cb2a8a_770x307.png 424w, /__u/substackcdn.com/image/fetch/$s_!-FJL!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134376ae-0a7f-4789-9f51-a935f6cb2a8a_770x307.png 848w, /__u/substackcdn.com/image/fetch/$s_!-FJL!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134376ae-0a7f-4789-9f51-a935f6cb2a8a_770x307.png 1272w, /__u/substackcdn.com/image/fetch/$s_!-FJL!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134376ae-0a7f-4789-9f51-a935f6cb2a8a_770x307.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Monitor <code>sdp.session.failed_total</code> broken down by failure reason. A spike in <code>ANSWER_TIMEOUT</code> indicates network issues. A spike in <code>CAS_REJECTED</code> means clients are retrying offers &#8212; usually a client-side bug or duplicate connection.</p><h2>Prerequisites</h2><p>Before running anything, confirm these tools are installed:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!txDL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31f60081-6c9f-431d-8304-b30a4a776bb9_663x267.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!txDL!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31f60081-6c9f-431d-8304-b30a4a776bb9_663x267.png 424w, /__u/substackcdn.com/image/fetch/$s_!txDL!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31f60081-6c9f-431d-8304-b30a4a776bb9_663x267.png 848w, /__u/substackcdn.com/image/fetch/$s_!txDL!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31f60081-6c9f-431d-8304-b30a4a776bb9_663x267.png 1272w, /__u/substackcdn.com/image/fetch/$s_!txDL!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31f60081-6c9f-431d-8304-b30a4a776bb9_663x267.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!txDL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31f60081-6c9f-431d-8304-b30a4a776bb9_663x267.png" width="469" height="188.8733031674208" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/31f60081-6c9f-431d-8304-b30a4a776bb9_663x267.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:267,&quot;width&quot;:663,&quot;resizeWidth&quot;:469,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="/__u/substackcdn.com/image/fetch/$s_!txDL!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31f60081-6c9f-431d-8304-b30a4a776bb9_663x267.png 424w, /__u/substackcdn.com/image/fetch/$s_!txDL!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31f60081-6c9f-431d-8304-b30a4a776bb9_663x267.png 848w, /__u/substackcdn.com/image/fetch/$s_!txDL!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31f60081-6c9f-431d-8304-b30a4a776bb9_663x267.png 1272w, /__u/substackcdn.com/image/fetch/$s_!txDL!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31f60081-6c9f-431d-8304-b30a4a776bb9_663x267.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><code>wscat</code><span> (optional) lets you send raw WebSocket messages manually during exploration. Install it with </span><code>npm install -g wscat</code><span> if you want to poke the server by hand.</span></p><h2>Build and Run</h2><p><strong>Step 1 &#8212; Generate the workspace</strong></p><pre><code><code>chmod +x project_setup.sh
./project_setup.sh
cd flux-day64</code></code></pre><p>This creates the full Maven project tree with all Java source files and lifecycle scripts.</p><p><strong>Step 2 &#8212; Start the server</strong></p><pre><code><code>./start.sh</code></code></pre><p><code>start.sh</code> compiles the project with Maven, packages it into a JAR, and starts the server in the background. It writes the server process ID to <code>.server.pid</code>.</p><pre><code><code>==&gt; Building flux-day64...
==&gt; Starting SDP Gateway (WS :8080, Dashboard :8081)...
==&gt; Server PID 84312
==&gt; Dashboard: http://localhost:8081/dashboard</code></code></pre><p>Two ports will be open:</p><ul><li><p><code>ws://localhost:8080</code> &#8212; WebSocket signaling endpoint</p></li><li><p><code>http://localhost:8081/dashboard</code> &#8212; live session dashboard</p></li></ul><h2>Running the Tests</h2><p>The unit test suite covers SDP parsing, all state transitions, the <code>fail()</code> spin-CAS loop, and a concurrent race test that verifies exactly one offer wins when 10 Virtual Threads compete simultaneously.</p><pre><code><code>mvn test</code></code></pre><p>Expected output:</p><pre><code><code>[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0</code></code></pre><h2>Running the Demo</h2><pre><code><code>./demo.sh</code></code></pre><p><code>demo.sh</code> runs <code>LoadTestClient</code> with 20 concurrent call pairs. Each simulated pair goes through the full handshake: OFFER &#8594; ANSWER &#8594; 3 ICE candidates &#8594; ESTABLISH. All 20 pairs run concurrently via Virtual Threads.</p><p>Watch the dashboard at <code>http://localhost:8081/dashboard</code> while the demo runs. You will see sessions appear in <code>OFFERING</code> state, transition through <code>ANSWERING</code>, and land on <code>ESTABLISHED</code> within a few hundred milliseconds.</p><p>Console output:</p><pre><code><code>[Load] Starting 20 call pairs on localhost:8080
[Load] Done. Success=20 Failed=0
==&gt; Done. Check dashboard: http://localhost:8081/dashboard</code></code></pre><h2>Verification</h2><pre><code><code>./verify.sh</code></code></pre><p><code>verify.sh</code> calls <code>/api/sessions</code> via <code>curl</code> and checks two things:</p><pre><code><code>==&gt; Verifying session state via API...
    Sessions established : 20
    CAS collisions       : 0
[PASS] At least one session reached ESTABLISHED
[PASS] No CAS collisions (clean state transitions)</code></code></pre><h2>Stopping and Cleaning Up</h2><p>To stop the running server without removing build artifacts:</p><pre><code><code>./stop.sh</code></code></pre><pre><code><code>==&gt; Stopped server PID 84312</code></code></pre><p>To remove build artifacts and log files (does not kill the server):</p><pre><code><code>./cleanup.sh</code></code></pre><pre><code><code>==&gt; Cleaning build artifacts...
==&gt; Done.</code></code></pre><p>When you want a completely clean slate, run <code>stop.sh</code> first, then <code>cleanup.sh</code>.</p><h2>Homework</h2><p><strong>Beginner:</strong> Add a <code>RINGING</code> state between <code>IDLE</code> and <code>OFFERING</code>. Implement a 30-second ring timeout that transitions the session to <code>FAILED</code> with reason <code>NO_ANSWER</code>.</p><p><strong>Intermediate:</strong> Replace the <code>String.split("\r?\n")</code> SDP parser with a <code>ByteBuffer</code>-based line scanner that avoids creating a <code>String[]</code> array entirely. Benchmark both with JMH and compare allocation rates.</p><p><strong>Expert:</strong> Implement SDP munging: before forwarding an OFFER to the callee, rewrite the <code>c=</code> (connection) line to point to your media relay server IP. This is what production TURN servers do to NAT-punch on behalf of clients behind symmetric NAT.</p>]]></content:encoded></item><item><title><![CDATA[Day 63 : Signaling Overlay: Voice State Update (Opcode 4)]]></title><description><![CDATA[STOMP normalizes all messages into a single subscription model.]]></description><link>https://javatsc.substack.com/p/day-63-signaling-overlay-voice-state</link><guid isPermaLink="false">https://javatsc.substack.com/p/day-63-signaling-overlay-voice-state</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Sat, 15 Aug 2026 01:46:36 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!YpXu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65978426-efc3-4730-be34-1fcaa506ccec_1125x650.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>STOMP normalizes all messages into a single subscription model. You lose opcode-level routing. You cannot distinguish a heartbeat from a voice state update without string-parsing the destination header. Worse, STOMP&#8217;s message broker is a synchronized <code>SimpleBrokerMessageHandler</code> &#8212; a single lock serializing every fan-out. At 10,000 concurrent voice state transitions (guild raid, concert stream ending), that lock is your bottleneck.</p><blockquote><p>Voice state is not a chat message. It is presence metadata that must be:</p><ul><li><p>Stored atomically</p></li><li><p>Fanned out only to guild channel members</p></li><li><p>Used downstream to bootstrap WebRTC signaling</p></li></ul><p>You need opcode-level dispatch. You need lock-free state storage. You need to own the entire path.</p></blockquote><div><hr></div><h2>The Failure Mode</h2><blockquote><p>Naive implementation: a <code>HashMap&lt;String, VoiceState&gt;</code> guarded by <code>synchronized</code>.</p><p>At 1M users joining voice channels simultaneously (think: a major game launch, a concert goes live), every VOICE_STATE_UPDATE (Opcode 4) acquires that lock. With average hold time of 200ns and 1M contenders, you are looking at 200 seconds of cumulative wait time per second of wall clock. Throughput collapses.</p><p>Second failure: storing <code>VoiceState</code> as mutable POJOs means you cannot safely read state mid-update without copying. Readers and writers race. You get torn reads &#8212; a user appears both in channel A and channel B simultaneously.</p><p>Third failure: fan-out. If you fan out to all guild members on the synchronized write path, you have coupled IO latency (slow clients) to your state update critical section. One slow WebSocket write blocks every other voice state update for that guild.</p></blockquote><div><hr></div><h2>The Flux Architecture</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!YpXu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65978426-efc3-4730-be34-1fcaa506ccec_1125x650.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!YpXu!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65978426-efc3-4730-be34-1fcaa506ccec_1125x650.png 424w, /__u/substackcdn.com/image/fetch/$s_!YpXu!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65978426-efc3-4730-be34-1fcaa506ccec_1125x650.png 848w, /__u/substackcdn.com/image/fetch/$s_!YpXu!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65978426-efc3-4730-be34-1fcaa506ccec_1125x650.png 1272w, /__u/substackcdn.com/image/fetch/$s_!YpXu!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65978426-efc3-4730-be34-1fcaa506ccec_1125x650.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!YpXu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65978426-efc3-4730-be34-1fcaa506ccec_1125x650.png" width="530" height="306.22222222222223" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/65978426-efc3-4730-be34-1fcaa506ccec_1125x650.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:650,&quot;width&quot;:1125,&quot;resizeWidth&quot;:530,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!YpXu!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65978426-efc3-4730-be34-1fcaa506ccec_1125x650.png 424w, /__u/substackcdn.com/image/fetch/$s_!YpXu!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65978426-efc3-4730-be34-1fcaa506ccec_1125x650.png 848w, /__u/substackcdn.com/image/fetch/$s_!YpXu!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65978426-efc3-4730-be34-1fcaa506ccec_1125x650.png 1272w, /__u/substackcdn.com/image/fetch/$s_!YpXu!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65978426-efc3-4730-be34-1fcaa506ccec_1125x650.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/javatsc.substack.com/p/day-63-signaling-overlay-voice-state">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Week 4: Leader Election & Reliable Execution (Days 16–20)]]></title><description><![CDATA[Why This Matters]]></description><link>https://javatsc.substack.com/p/week-4-leader-election-and-reliable</link><guid isPermaLink="false">https://javatsc.substack.com/p/week-4-leader-election-and-reliable</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Thu, 13 Aug 2026 02:31:24 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!NQ6Z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6a4391-9073-4fc0-b811-6aed32f44e08_1062x650.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Why This Matters</h2><blockquote><p>When Uber dispatches surge-pricing jobs, when Netflix refreshes CDN caches, or when your bank runs end-of-day reconciliation, <strong>exactly one scheduler instance</strong> must decide <em>what</em> runs and <em>when</em>. Run the same cron on every pod and you double-charge customers. Run none and reports never ship.</p><p>The fix is not &#8220;turn off scheduling on followers.&#8221; You need an explicit <strong>leader election</strong> contract, <strong>lease-based heartbeats</strong>, <strong>automatic failover</strong>, <strong>coordination primitives</strong>, and <strong>idempotent execution</strong> so retries never corrupt state.</p></blockquote><h2>What We Built</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!I7rw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66e164ac-7f67-4b44-a6f8-bdaeadf14a89_820x341.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!I7rw!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66e164ac-7f67-4b44-a6f8-bdaeadf14a89_820x341.png 424w, /__u/substackcdn.com/image/fetch/$s_!I7rw!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66e164ac-7f67-4b44-a6f8-bdaeadf14a89_820x341.png 848w, /__u/substackcdn.com/image/fetch/$s_!I7rw!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66e164ac-7f67-4b44-a6f8-bdaeadf14a89_820x341.png 1272w, /__u/substackcdn.com/image/fetch/$s_!I7rw!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66e164ac-7f67-4b44-a6f8-bdaeadf14a89_820x341.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!I7rw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66e164ac-7f67-4b44-a6f8-bdaeadf14a89_820x341.png" width="820" height="341" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/66e164ac-7f67-4b44-a6f8-bdaeadf14a89_820x341.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:341,&quot;width&quot;:820,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:44005,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://javatsc.substack.com/i/207122112?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66e164ac-7f67-4b44-a6f8-bdaeadf14a89_820x341.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!I7rw!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66e164ac-7f67-4b44-a6f8-bdaeadf14a89_820x341.png 424w, /__u/substackcdn.com/image/fetch/$s_!I7rw!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66e164ac-7f67-4b44-a6f8-bdaeadf14a89_820x341.png 848w, /__u/substackcdn.com/image/fetch/$s_!I7rw!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66e164ac-7f67-4b44-a6f8-bdaeadf14a89_820x341.png 1272w, /__u/substackcdn.com/image/fetch/$s_!I7rw!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66e164ac-7f67-4b44-a6f8-bdaeadf14a89_820x341.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Core Concepts</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!NQ6Z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6a4391-9073-4fc0-b811-6aed32f44e08_1062x650.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!NQ6Z!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6a4391-9073-4fc0-b811-6aed32f44e08_1062x650.png 424w, /__u/substackcdn.com/image/fetch/$s_!NQ6Z!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6a4391-9073-4fc0-b811-6aed32f44e08_1062x650.png 848w, /__u/substackcdn.com/image/fetch/$s_!NQ6Z!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6a4391-9073-4fc0-b811-6aed32f44e08_1062x650.png 1272w, /__u/substackcdn.com/image/fetch/$s_!NQ6Z!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6a4391-9073-4fc0-b811-6aed32f44e08_1062x650.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!NQ6Z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6a4391-9073-4fc0-b811-6aed32f44e08_1062x650.png" width="508" height="310.92278719397365" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4c6a4391-9073-4fc0-b811-6aed32f44e08_1062x650.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:650,&quot;width&quot;:1062,&quot;resizeWidth&quot;:508,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!NQ6Z!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6a4391-9073-4fc0-b811-6aed32f44e08_1062x650.png 424w, /__u/substackcdn.com/image/fetch/$s_!NQ6Z!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6a4391-9073-4fc0-b811-6aed32f44e08_1062x650.png 848w, /__u/substackcdn.com/image/fetch/$s_!NQ6Z!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6a4391-9073-4fc0-b811-6aed32f44e08_1062x650.png 1272w, /__u/substackcdn.com/image/fetch/$s_!NQ6Z!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c6a4391-9073-4fc0-b811-6aed32f44e08_1062x650.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>1. Single-Active Scheduler Pattern</h3><p>In a horizontally scaled cluster, one node holds a <strong>lease</strong> in shared storage. The lease has an expiry timestamp. The leader renews it on a heartbeat interval (typically one-third of lease duration). Followers observe an unexpired lease owned by someone else and stay idle.</p><p>This is how Google&#8217;s Chubby-inspired systems, Kubernetes lease objects, and JDBC-backed Spring schedulers keep one brain in charge.</p><h3>2. Database-Backed Leases</h3><p>PostgreSQL stores a <code>cluster_leadership</code> row per service. Acquisition uses optimistic versioning plus conditional updates:</p><ul><li><p><strong>Renew:</strong> update only if you still own a non-expired lease</p></li><li><p><strong>Takeover:</strong> update only if the lease is expired</p></li><li><p><strong>Failover:</strong> force-expire a stale leader after health checks fail</p></li></ul>
      <p>
          <a href="/__u/javatsc.substack.com/p/week-4-leader-election-and-reliable">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 62: WebRTC Basics — SDP and ICE Candidates]]></title><description><![CDATA[The &#8220;Spring Boot&#8221; Trap]]></description><link>https://javatsc.substack.com/p/day-62-webrtc-basics-sdp-and-ice</link><guid isPermaLink="false">https://javatsc.substack.com/p/day-62-webrtc-basics-sdp-and-ice</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Wed, 12 Aug 2026 01:45:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!QZZw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9918e97c-8602-44ac-88e0-a6653650138f_4500x2800.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>The &#8220;Spring Boot&#8221; Trap</h2><blockquote><p>A junior engineer tasked with &#8220;adding voice calling&#8221; reaches for a WebRTC library. They drop in <code>webrtc4j</code> or a JavaScript SDK, annotate a controller with <code>@MessageMapping</code>, and call it done. The signaling layer &#8212; the server-side component that brokers SDP offers, answers, and ICE candidates between two peers &#8212; becomes a thin relay: receive JSON blob, forward JSON blob. It works in a demo with two browser tabs.</p><p>The trap is what&#8217;s hidden: that JSON blob is a full SDP offer. It&#8217;s 2&#8211;5 KB of plaintext describing codec preferences, DTLS fingerprints, RTP payload types, and extension headers. At 100K concurrent call setups, a naive implementation is doing 500 MB/s of String allocation just for SDP parsing. Jackson&#8217;s <code>ObjectMapper</code> deserializes each offer into a full object graph &#8212; dozens of nested nodes, each a heap allocation, each a GC liability.</p><p>Worse: the framework hides the session lifecycle entirely. When a <code>@MessageMapping</code> handler loses its WebSocket connection mid-negotiation, what happens to the in-flight SDP exchange? With Spring&#8217;s abstraction, the answer is: you don&#8217;t know. The session state evaporates, and neither peer gets a clean error. At scale, that means orphaned ICE candidate buffers accumulating in memory with no cleanup path.</p></blockquote><div><hr></div><h2>The Failure Mode</h2><blockquote><p><strong>Eden Space Exhaustion from SDP Churn</strong></p><p>SDP is text-heavy by design. A typical offer contains 40&#8211;80 lines, each a <code>String.split()</code>-able field. In Java, <code>String.split()</code> compiles a <code>Pattern</code>, allocates a <code>String[]</code>, then allocates each substring. For a 60-line SDP parsed with <code>split("\r\n")</code> followed by per-line <code>split("=", 2)</code>, you&#8217;re looking at 180+ allocations per offer &#8212; all short-lived, all Eden-bound.</p><p>At 10K calls/second (a modest mid-size platform), that&#8217;s 1.8M allocations per second purely from SDP parsing. Minor GC pauses hit every few hundred milliseconds. At 100K calls/second, you&#8217;re triggering GC so frequently that throughput collapses before you&#8217;ve forwarded a single RTP packet.</p><p><strong>ICE Candidate Trickle Storm</strong></p><p>ICE trickle means candidates arrive asynchronously &#8212; a caller may send 5&#8211;15 <code>candidate:</code> lines over several seconds. A naive session store using <code>HashMap&lt;String, List&lt;IceCandidate&gt;&gt;</code> with boxed keys allocates constantly. More critically, if the session state machine is unguarded, a late-arriving candidate for an already-closed session has no clean rejection path &#8212; it inserts into a map for a session that&#8217;s been garbage collected, holding the map entry live indefinitely.</p><p><strong>The Reconnect Signaling Storm</strong></p><p>When a server restarts or a region fails over, thousands of clients reconnect simultaneously and immediately attempt to re-establish calls. Every one of them sends a new SDP offer. If your signaling router processes these synchronously on a thread pool, you exhaust the pool. Queued sessions time out before being processed, generating a cascade of retries that amplifies the load 3&#8211;5&#215;.</p></blockquote><div><hr></div><h2>The Flux Architecture</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!QZZw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9918e97c-8602-44ac-88e0-a6653650138f_4500x2800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!QZZw!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9918e97c-8602-44ac-88e0-a6653650138f_4500x2800.png 424w, /__u/substackcdn.com/image/fetch/$s_!QZZw!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9918e97c-8602-44ac-88e0-a6653650138f_4500x2800.png 848w, /__u/substackcdn.com/image/fetch/$s_!QZZw!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9918e97c-8602-44ac-88e0-a6653650138f_4500x2800.png 1272w, /__u/substackcdn.com/image/fetch/$s_!QZZw!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9918e97c-8602-44ac-88e0-a6653650138f_4500x2800.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!QZZw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9918e97c-8602-44ac-88e0-a6653650138f_4500x2800.png" width="532" height="331.03846153846155" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9918e97c-8602-44ac-88e0-a6653650138f_4500x2800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:906,&quot;width&quot;:1456,&quot;resizeWidth&quot;:532,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!QZZw!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9918e97c-8602-44ac-88e0-a6653650138f_4500x2800.png 424w, /__u/substackcdn.com/image/fetch/$s_!QZZw!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9918e97c-8602-44ac-88e0-a6653650138f_4500x2800.png 848w, /__u/substackcdn.com/image/fetch/$s_!QZZw!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9918e97c-8602-44ac-88e0-a6653650138f_4500x2800.png 1272w, /__u/substackcdn.com/image/fetch/$s_!QZZw!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9918e97c-8602-44ac-88e0-a6653650138f_4500x2800.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/javatsc.substack.com/p/day-62-webrtc-basics-sdp-and-ice">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 61 :UDP vs TCP: Coding a Raw Packet Echo Server]]></title><description><![CDATA[The Spring Boot Trap]]></description><link>https://javatsc.substack.com/p/day-61-udp-vs-tcp-coding-a-raw-packet</link><guid isPermaLink="false">https://javatsc.substack.com/p/day-61-udp-vs-tcp-coding-a-raw-packet</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Sun, 09 Aug 2026 01:45:23 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!fsLG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd83121bb-0ae1-414b-9bae-6ec4548d5421_1125x700.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>The Spring Boot Trap</h2><blockquote><p>A junior engineer wiring up voice chat reaches for Spring Boot&#8217;s <code>@EnableWebSocket</code> and wraps everything in TCP. It works on their laptop with two friends. Ship it.</p><p>Then reality hits: voice audio is 20ms Opus frames arriving at 50 packets/second per user. At 10,000 concurrent speakers that&#8217;s 500,000 packets/sec. TCP&#8217;s retransmit-and-wait semantic &#8212; built for reliability &#8212; becomes your enemy. A single dropped packet stalls the receive buffer until the OS retransmits. You hear a half-second freeze. Every. Single. Time.</p><p>WebRTC doesn&#8217;t use TCP for media. It uses UDP. Not because UDP is &#8220;faster&#8221; in some hand-wavy sense, but because for real-time media <strong>a stale packet is worse than no packet</strong>. If an Opus frame is 20ms late, you don&#8217;t want it. You want to interpolate silence and move on.</p><p>Spring Boot hides this. It gives you a nice <code>WebSocketHandler</code>, a <code>TextMessage</code>, and zero control over the transport layer beneath it. You cannot drop into raw UDP. You cannot tune socket receive buffers. You cannot implement DTLS yourself. You are building audio on top of a framework that was never designed for it.</p></blockquote><div><hr></div><h2>The Failure Mode</h2><blockquote><p>Here&#8217;s what a naive UDP server looks like in Java before this lesson:</p></blockquote><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;d5b4c159-12d7-47b8-b03a-ba2f734ec7fe&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">DatagramSocket socket = new DatagramSocket(5005);
byte[] buf = new byte[1500];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
while (true) {
    socket.receive(packet); // BLOCKS the calling thread
    socket.send(packet);
}</code></pre></div><blockquote><p>One thread. Blocking receive. This hits the OS kernel&#8217;s receive buffer at ~50K packets/sec on a modern NIC. Anything beyond that gets silently dropped &#8212; no exception, no log. It just disappears.</p><p>Scale this: spawn a thread per client. 10,000 clients = 10,000 OS threads. At 1MB stack each, that&#8217;s 10GB of virtual address space before you&#8217;ve processed a single byte of audio. The OS scheduler starts spending more time context-switching than running your code.</p><p>The second failure: <code>new byte[1500]</code> inside the receive loop. Each UDP packet allocation goes to the JVM Eden space. At 500K packets/sec that&#8217;s 750MB/sec of allocation pressure. The GC fires a minor collection every few hundred milliseconds. During that pause &#8212; which lasts 5&#8211;50ms on a busy heap &#8212; your receive loop stops. The OS kernel&#8217;s socket receive buffer fills up. UDP packets are dropped. Users hear glitches.</p><p>You cannot afford GC pauses in a media path.</p></blockquote><div><hr></div><h2><strong>The Flux Architecture</strong></h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!fsLG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd83121bb-0ae1-414b-9bae-6ec4548d5421_1125x700.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!fsLG!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd83121bb-0ae1-414b-9bae-6ec4548d5421_1125x700.png 424w, /__u/substackcdn.com/image/fetch/$s_!fsLG!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd83121bb-0ae1-414b-9bae-6ec4548d5421_1125x700.png 848w, /__u/substackcdn.com/image/fetch/$s_!fsLG!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd83121bb-0ae1-414b-9bae-6ec4548d5421_1125x700.png 1272w, /__u/substackcdn.com/image/fetch/$s_!fsLG!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd83121bb-0ae1-414b-9bae-6ec4548d5421_1125x700.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!fsLG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd83121bb-0ae1-414b-9bae-6ec4548d5421_1125x700.png" width="544" height="338.4888888888889" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d83121bb-0ae1-414b-9bae-6ec4548d5421_1125x700.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:700,&quot;width&quot;:1125,&quot;resizeWidth&quot;:544,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!fsLG!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd83121bb-0ae1-414b-9bae-6ec4548d5421_1125x700.png 424w, /__u/substackcdn.com/image/fetch/$s_!fsLG!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd83121bb-0ae1-414b-9bae-6ec4548d5421_1125x700.png 848w, /__u/substackcdn.com/image/fetch/$s_!fsLG!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd83121bb-0ae1-414b-9bae-6ec4548d5421_1125x700.png 1272w, /__u/substackcdn.com/image/fetch/$s_!fsLG!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd83121bb-0ae1-414b-9bae-6ec4548d5421_1125x700.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/javatsc.substack.com/p/day-61-udp-vs-tcp-coding-a-raw-packet">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Week 3: Distributed Locking (Days 11–15)]]></title><description><![CDATA[Why This Matters]]></description><link>https://javatsc.substack.com/p/week-3-distributed-locking-days-1115</link><guid isPermaLink="false">https://javatsc.substack.com/p/week-3-distributed-locking-days-1115</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Fri, 07 Aug 2026 02:30:31 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!cDG4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eabdef9-311e-44e2-814e-6c7d61e9b49d_1062x625.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Why This Matters</h2><blockquote><p>You already have a catalog of schedules and a binder that turns rows into <code>ScheduledFuture</code>s. That is a control plane. Horizontal scale breaks it the moment two JVMs share the same catalog: each node still wakes on the same cron, and both happily &#8220;reconcile invoices&#8221; at 02:00. Payment platforms call that double-settlement. Warehouse systems call it double-ship. Schedulers call it <em>the reason locks exist</em>.</p><p>Airflow&#8217;s executors, Kubernetes leader election for controllers, and Redis-backed queue claim patterns all solve variants of the same question: <strong>among N healthy processes, which one may enter this critical section right now?</strong> integrated lab &#8212; <strong>Aegis</strong> &#8212; makes that question tangible. You will watch unprotected ticks collide, then enforce exclusion with database leases, optimistic claims, Redis <code>SET NX</code>, and a Redlock quorum &#8212; one dashboard, no toy mocks.</p><p>The production insight that separates junior from senior designs is not &#8220;use Redis.&#8221; It is knowing <strong>which failure mode your lock actually covers</strong>. A Postgres <code>SELECT FOR UPDATE</code> and a Redis key with TTL fail differently under network partitions. Product managers feel those differences as duplicate emails; SREs feel them as pager storms; architects must name them before choosing a store.</p></blockquote><h2>Agenda</h2><blockquote><ol><li><p>The single-instance illusion after scale-out</p></li><li><p>Where locks sit in the Task Scheduler architecture</p></li><li><p>Control flow: tick &#8594; acquire &#8594; run &#8594; release</p></li><li><p>Data flow across RDBMS and Redis</p></li><li><p>Lock and task state machines</p></li><li><p>Four real coordination strategies (plus the &#8220;none&#8221; baseline)</p></li><li><p>Build, test, and demo Aegis</p></li><li><p>Production trade-offs and homework</p></li></ol></blockquote><h2>The Problem Being Solved</h2><blockquote><p>Static <code>@Scheduled</code> methods are process-local. Persist the schedule in a database and every replica will still fire. Without a distributed lock, your audit table fills with two <code>EXECUTED</code> rows for the same logical tick &#8212; different <code>instanceId</code>, same business effect.</p><p>That is not a logging bug. It is a <strong>missing mutual-exclusion boundary</strong> around work that is not idempotent. Even idempotent handlers benefit from locks: you save CPU, cache stampedes, and load on downstream banks or SaaS APIs that rate-limit by account.</p></blockquote><h2>Why It Matters in Distributed Systems</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!cDG4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eabdef9-311e-44e2-814e-6c7d61e9b49d_1062x625.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!cDG4!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eabdef9-311e-44e2-814e-6c7d61e9b49d_1062x625.png 424w, /__u/substackcdn.com/image/fetch/$s_!cDG4!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eabdef9-311e-44e2-814e-6c7d61e9b49d_1062x625.png 848w, /__u/substackcdn.com/image/fetch/$s_!cDG4!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eabdef9-311e-44e2-814e-6c7d61e9b49d_1062x625.png 1272w, /__u/substackcdn.com/image/fetch/$s_!cDG4!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eabdef9-311e-44e2-814e-6c7d61e9b49d_1062x625.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!cDG4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eabdef9-311e-44e2-814e-6c7d61e9b49d_1062x625.png" width="504" height="296.6101694915254" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8eabdef9-311e-44e2-814e-6c7d61e9b49d_1062x625.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:625,&quot;width&quot;:1062,&quot;resizeWidth&quot;:504,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!cDG4!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eabdef9-311e-44e2-814e-6c7d61e9b49d_1062x625.png 424w, /__u/substackcdn.com/image/fetch/$s_!cDG4!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eabdef9-311e-44e2-814e-6c7d61e9b49d_1062x625.png 848w, /__u/substackcdn.com/image/fetch/$s_!cDG4!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eabdef9-311e-44e2-814e-6c7d61e9b49d_1062x625.png 1272w, /__u/substackcdn.com/image/fetch/$s_!cDG4!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eabdef9-311e-44e2-814e-6c7d61e9b49d_1062x625.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/javatsc.substack.com/p/week-3-distributed-locking-days-1115">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 60: Gateway Observability — Metrics for Connected Clients and Events Per Second]]></title><description><![CDATA[The &#8220;Spring Boot&#8221; Trap]]></description><link>https://javatsc.substack.com/p/day-60-gateway-observability-metrics</link><guid isPermaLink="false">https://javatsc.substack.com/p/day-60-gateway-observability-metrics</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Thu, 06 Aug 2026 01:46:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!kdoE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F472d52aa-8375-4e7e-ad52-c5e0666b54c3_1125x700.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>The &#8220;Spring Boot&#8221; Trap</h2><blockquote><p>A junior engineer wires up Spring Boot Actuator, adds <code>spring-boot-starter-actuator</code> to the POM, and calls it done. They get <code>/actuator/metrics/jvm.memory.used</code> out of the box. Beautiful, until they look at what that costs.</p><p>Spring Actuator&#8217;s default <code>MeterRegistry</code> uses <code>AtomicLong</code> for every counter. Under load &#8212; 50,000 connection events per second &#8212; every increment is a compare-and-swap on a shared cache line. The CPU burns cycles retrying failed CAS operations as threads collide. At 10 threads that&#8217;s noise. At 500 Virtual Threads funneling connection events, that&#8217;s measurable throughput degradation. You&#8217;ve added observability that slows down the thing you&#8217;re observing.</p><p>The second trap: metric collection tied to the request path. If scraping your <code>/metrics</code> endpoint blocks on the same lock that your connection handler uses to update state, you&#8217;ve just made Prometheus scrapes into a latency spike for every client connected at that moment.</p><p>The third trap: string formatting. Spring formats metric names and labels on every read. <code>String.format("gateway_events{server='%s'}", hostname)</code> in a tight loop allocates heap on every invocation. At 1M events/minute, you&#8217;re feeding the GC constantly.</p></blockquote><div><hr></div><h2>The Failure Mode</h2><blockquote><p>The naive implementation collapses under two forces simultaneously.</p><p><strong>Cache line contention</strong>: An <code>AtomicInteger</code> is 16 bytes. Under JVM object layout, a hot counter sits on a 64-byte CPU cache line. When 500 Virtual Threads all increment it, the L3 cache must arbitrate ownership of that cache line across CPU cores. Intel MESIF protocol means each increment &#8212; fetch, modify, write-back &#8212; stalls other cores. You get cache line bouncing, visible as elevated <code>LLC-load-misses</code> in <code>perf stat</code> output. Throughput flatlines at ~2M increments/second where the unconstrained math says 100M+.</p><p><strong>Eden space pressure from metric labels</strong>: Prometheus exposition format requires label strings. Generating <code>gateway_events_total{shard="3",type="MESSAGE"}\n</code> on every scrape via naive concatenation creates one <code>String</code> object per metric per scrape interval. At 200 metrics, scraped every 15 seconds, that&#8217;s manageable. But if you push metrics instead of pull &#8212; formatting on every event &#8212; you&#8217;ve turned your metrics layer into an allocation firehose.</p><p><strong>The rate calculation trap</strong>: Storing raw event timestamps to calculate events-per-second means <code>ArrayList&lt;Long&gt;</code> growing unbounded. At 10,000 events/second, you&#8217;re storing 600,000 longs per minute before any GC has a chance to clean up. The heap inflates. Stop-the-world pauses start showing up at the worst moments &#8212; during traffic spikes, precisely when you need accurate metrics most.</p></blockquote><div><hr></div><h2>The Flux Architecture</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!kdoE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F472d52aa-8375-4e7e-ad52-c5e0666b54c3_1125x700.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!kdoE!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F472d52aa-8375-4e7e-ad52-c5e0666b54c3_1125x700.png 424w, /__u/substackcdn.com/image/fetch/$s_!kdoE!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F472d52aa-8375-4e7e-ad52-c5e0666b54c3_1125x700.png 848w, /__u/substackcdn.com/image/fetch/$s_!kdoE!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F472d52aa-8375-4e7e-ad52-c5e0666b54c3_1125x700.png 1272w, /__u/substackcdn.com/image/fetch/$s_!kdoE!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F472d52aa-8375-4e7e-ad52-c5e0666b54c3_1125x700.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!kdoE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F472d52aa-8375-4e7e-ad52-c5e0666b54c3_1125x700.png" width="552" height="343.46666666666664" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/472d52aa-8375-4e7e-ad52-c5e0666b54c3_1125x700.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:700,&quot;width&quot;:1125,&quot;resizeWidth&quot;:552,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!kdoE!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F472d52aa-8375-4e7e-ad52-c5e0666b54c3_1125x700.png 424w, /__u/substackcdn.com/image/fetch/$s_!kdoE!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F472d52aa-8375-4e7e-ad52-c5e0666b54c3_1125x700.png 848w, /__u/substackcdn.com/image/fetch/$s_!kdoE!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F472d52aa-8375-4e7e-ad52-c5e0666b54c3_1125x700.png 1272w, /__u/substackcdn.com/image/fetch/$s_!kdoE!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F472d52aa-8375-4e7e-ad52-c5e0666b54c3_1125x700.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Three principles drive the observability layer:</p><p><strong>Wait-free counters via </strong><code>LongAdder</code>: Java&#8217;s <code>LongAdder</code> uses Striped64 internals &#8212; it maintains an array of <code>Cell</code> objects, each pinned to a thread group via a hash of the thread ID. Increments write to thread-local cells. Reads sum all cells. No CAS contention on increments because threads rarely collide. The tradeoff is that reads are slightly stale &#8212; the sum is eventually consistent, not instantaneous. For Prometheus metrics scraped every 15 seconds, this is irrelevant.</p><p><strong>Ring buffer for rate calculation</strong>: Events Per Second is computed over a sliding window. Instead of storing every timestamp, a fixed-size ring buffer of slot counters tracks events per 100ms bucket. EPS = sum of last 10 buckets / 1 second. The ring buffer is pre-allocated at startup &#8212; no heap allocation on the hot path, ever.</p><p><strong>Pre-formatted label strings</strong>: Metric names and labels are computed once at registration and cached as <code>byte[]</code>. The Prometheus exposition format writer copies pre-built byte arrays into the response buffer. Zero <code>String</code> allocation during scrape.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!EmE7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b6d7589-effb-481e-804b-acfb64a8f8e7_1125x775.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!EmE7!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b6d7589-effb-481e-804b-acfb64a8f8e7_1125x775.png 424w, /__u/substackcdn.com/image/fetch/$s_!EmE7!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b6d7589-effb-481e-804b-acfb64a8f8e7_1125x775.png 848w, /__u/substackcdn.com/image/fetch/$s_!EmE7!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b6d7589-effb-481e-804b-acfb64a8f8e7_1125x775.png 1272w, /__u/substackcdn.com/image/fetch/$s_!EmE7!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b6d7589-effb-481e-804b-acfb64a8f8e7_1125x775.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!EmE7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b6d7589-effb-481e-804b-acfb64a8f8e7_1125x775.png" width="536" height="369.24444444444447" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1b6d7589-effb-481e-804b-acfb64a8f8e7_1125x775.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:775,&quot;width&quot;:1125,&quot;resizeWidth&quot;:536,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!EmE7!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b6d7589-effb-481e-804b-acfb64a8f8e7_1125x775.png 424w, /__u/substackcdn.com/image/fetch/$s_!EmE7!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b6d7589-effb-481e-804b-acfb64a8f8e7_1125x775.png 848w, /__u/substackcdn.com/image/fetch/$s_!EmE7!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b6d7589-effb-481e-804b-acfb64a8f8e7_1125x775.png 1272w, /__u/substackcdn.com/image/fetch/$s_!EmE7!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b6d7589-effb-481e-804b-acfb64a8f8e7_1125x775.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>Implementation Deep Dive</h2><h3>GitHub Link :</h3><p><a href="https://github.com/sysdr/discord-flux-p/tree/main/day60/flux-gateway-observability">https://github.com/sysdr/discord-flux-p/tree/main/day60/flux-gateway-observability</a></p><p><code>LongAdder</code><strong> as gauge delta</strong>: Connected client count is a gauge, not a counter. On connect, call <code>connectedClients.increment()</code>. On disconnect, call <code>connectedClients.decrement()</code>. The <code>longValue()</code> at scrape time gives the current snapshot. The JVM&#8217;s Striped64 implementation handles the summation across cells under the hood.</p><p><code>EventRateCalculator</code><strong> ring buffer</strong>: The calculator maintains a <code>LongAdder[] buckets</code> array of size 100 (100 buckets &#215; 100ms = 10 seconds of history). A <code>currentBucket</code> index advances every 100ms via a <code>ScheduledExecutorService</code> using a Virtual Thread factory. On advance, the old bucket is zeroed. EPS is <code>sum(buckets) / 10.0</code>. This is O(1) on the write path &#8212; just <code>buckets[currentBucket].increment()</code> &#8212; with no synchronization needed on the hot path.</p><p><strong>VarHandle for atomic bucket index</strong>: The <code>currentBucket</code> pointer uses <code>VarHandle.getAndAdd()</code> with modular arithmetic. This is cheaper than <code>AtomicInteger</code> for this access pattern because we only need release/acquire semantics, not full sequential consistency.</p><p><strong>Prometheus text format</strong>: The exposition format is dead simple:</p><pre><code><code># HELP gateway_connected_clients Current number of connected WebSocket clients
# TYPE gateway_connected_clients gauge
gateway_connected_clients 4821
# HELP gateway_events_per_second Event processing rate
# TYPE gateway_events_per_second gauge
gateway_events_per_second 12847.30</code></code></pre><p>Pre-build the <code># HELP</code> and <code># TYPE</code> lines as <code>byte[]</code> at startup. At scrape time, concatenate with the current value formatted via <code>Long.toString()</code> &#8212; the only allocation.</p><p><strong>Virtual Thread HTTP server</strong>: The metrics HTTP server uses <code>com.sun.net.httpserver.HttpServer</code> with a Virtual Thread executor. Each Prometheus scrape gets its own Virtual Thread. Since scrapes are I/O bound (write response, flush socket), Virtual Threads park during the write and yield the carrier. No blocking, no wasted platform threads.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!Fhu9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99acecd3-4b35-4413-9d0e-21a603b9e30d_1250x875.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!Fhu9!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99acecd3-4b35-4413-9d0e-21a603b9e30d_1250x875.png 424w, /__u/substackcdn.com/image/fetch/$s_!Fhu9!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99acecd3-4b35-4413-9d0e-21a603b9e30d_1250x875.png 848w, /__u/substackcdn.com/image/fetch/$s_!Fhu9!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99acecd3-4b35-4413-9d0e-21a603b9e30d_1250x875.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Fhu9!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99acecd3-4b35-4413-9d0e-21a603b9e30d_1250x875.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!Fhu9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99acecd3-4b35-4413-9d0e-21a603b9e30d_1250x875.png" width="526" height="368.2" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/99acecd3-4b35-4413-9d0e-21a603b9e30d_1250x875.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:875,&quot;width&quot;:1250,&quot;resizeWidth&quot;:526,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!Fhu9!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99acecd3-4b35-4413-9d0e-21a603b9e30d_1250x875.png 424w, /__u/substackcdn.com/image/fetch/$s_!Fhu9!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99acecd3-4b35-4413-9d0e-21a603b9e30d_1250x875.png 848w, /__u/substackcdn.com/image/fetch/$s_!Fhu9!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99acecd3-4b35-4413-9d0e-21a603b9e30d_1250x875.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Fhu9!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99acecd3-4b35-4413-9d0e-21a603b9e30d_1250x875.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>Class Reference</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!tNOD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d5a54a5-429b-4820-8596-fe9ccd577874_923x393.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!tNOD!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d5a54a5-429b-4820-8596-fe9ccd577874_923x393.png 424w, /__u/substackcdn.com/image/fetch/$s_!tNOD!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d5a54a5-429b-4820-8596-fe9ccd577874_923x393.png 848w, /__u/substackcdn.com/image/fetch/$s_!tNOD!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d5a54a5-429b-4820-8596-fe9ccd577874_923x393.png 1272w, /__u/substackcdn.com/image/fetch/$s_!tNOD!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d5a54a5-429b-4820-8596-fe9ccd577874_923x393.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!tNOD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d5a54a5-429b-4820-8596-fe9ccd577874_923x393.png" width="923" height="393" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2d5a54a5-429b-4820-8596-fe9ccd577874_923x393.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:393,&quot;width&quot;:923,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:56802,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://javatsc.substack.com/i/203375369?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d5a54a5-429b-4820-8596-fe9ccd577874_923x393.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!tNOD!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d5a54a5-429b-4820-8596-fe9ccd577874_923x393.png 424w, /__u/substackcdn.com/image/fetch/$s_!tNOD!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d5a54a5-429b-4820-8596-fe9ccd577874_923x393.png 848w, /__u/substackcdn.com/image/fetch/$s_!tNOD!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d5a54a5-429b-4820-8596-fe9ccd577874_923x393.png 1272w, /__u/substackcdn.com/image/fetch/$s_!tNOD!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d5a54a5-429b-4820-8596-fe9ccd577874_923x393.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h3>Working Demo Link :</h3><div id="youtube2-DDtZhR2pER8" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;DDtZhR2pER8&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/DDtZhR2pER8?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h2>Production Readiness</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!WFmY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2c43f8d-11da-4088-883b-323311a43892_843x337.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!WFmY!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2c43f8d-11da-4088-883b-323311a43892_843x337.png 424w, /__u/substackcdn.com/image/fetch/$s_!WFmY!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2c43f8d-11da-4088-883b-323311a43892_843x337.png 848w, /__u/substackcdn.com/image/fetch/$s_!WFmY!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2c43f8d-11da-4088-883b-323311a43892_843x337.png 1272w, /__u/substackcdn.com/image/fetch/$s_!WFmY!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2c43f8d-11da-4088-883b-323311a43892_843x337.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!WFmY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2c43f8d-11da-4088-883b-323311a43892_843x337.png" width="843" height="337" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b2c43f8d-11da-4088-883b-323311a43892_843x337.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:337,&quot;width&quot;:843,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:46930,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://javatsc.substack.com/i/203375369?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2c43f8d-11da-4088-883b-323311a43892_843x337.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!WFmY!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2c43f8d-11da-4088-883b-323311a43892_843x337.png 424w, /__u/substackcdn.com/image/fetch/$s_!WFmY!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2c43f8d-11da-4088-883b-323311a43892_843x337.png 848w, /__u/substackcdn.com/image/fetch/$s_!WFmY!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2c43f8d-11da-4088-883b-323311a43892_843x337.png 1272w, /__u/substackcdn.com/image/fetch/$s_!WFmY!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2c43f8d-11da-4088-883b-323311a43892_843x337.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The carrier thread count is the canary. If Virtual Threads are parking correctly on I/O, you should see exactly N platform threads (where N = available CPUs) doing real work. If the count grows, something is blocking a carrier &#8212; a <code>synchronized</code> block, a native call, or a pinned Virtual Thread.</p><p><strong>Key </strong><code>jcmd</code><strong> commands</strong>:</p><pre><code><code># Thread dump to catch pinned virtual threads
jcmd &lt;pid&gt; Thread.dump_to_file -format=json /tmp/threads.json

# GC stats
jcmd &lt;pid&gt; GC.heap_info

# Live memory
jcmd &lt;pid&gt; VM.native_memory</code></code></pre><p><strong>Heap vs off-heap</strong>: The ring buffer and pre-formatted label bytes live on-heap but are long-lived &#8212; they&#8217;ll be promoted to Old Gen immediately and rarely GC&#8217;d. The allocation rate should be near zero for the metrics layer itself. If you see consistent Eden allocation from the metrics package, you&#8217;ve got a formatting leak.</p><div><hr></div><h2>Build and Run</h2><h3>Prerequisites</h3><ul><li><p>JDK 21+</p></li><li><p>Maven 3.9+</p></li><li><p>VisualVM 2.x (for thread/heap observation)</p></li><li><p><code>curl</code> (for endpoint verification)</p></li><li><p><code>python3</code> (optional, for JSON pretty-print in <code>verify.sh</code>)</p></li></ul><h3>Setup and Start</h3><pre><code><code>cd flux-gateway-observability
chmod +x start.sh demo.sh verify.sh stop.sh cleanup.sh
./start.sh</code></code></pre><p>Expected output:</p><pre><code><code>==&gt; Building flux-gateway-observability...
==&gt; Starting server...
=== Flux Gateway Observability &#8212; Day 60 ===
[ObservabilityHttpServer] http://localhost:8080/dashboard
[ObservabilityHttpServer] Prometheus: http://localhost:8080/metrics
[main] Gateway on :7777
[main] Dashboard at http://localhost:8080/dashboard
[main] Prometheus at http://localhost:8080/metrics
[main] Press Ctrl+C to stop.
[GatewayServer] listening on :7777</code></code></pre><h3>Run the Load Generator</h3><p>In a second terminal:</p><pre><code><code>cd flux-gateway-observability
./demo.sh</code></code></pre><p>Expected output:</p><pre><code><code>[LoadGen] starting 50 clients @ 10 events/s each for 30s
[LoadGen] sent=1024 errors=0 remaining=28s
[LoadGen] sent=3148 errors=0 remaining=26s
...
[LoadGen] done. total_sent=15000 total_errors=0</code></code></pre><h3>Verify All Endpoints</h3><pre><code><code>./verify.sh</code></code></pre><p>Expected output:</p><pre><code><code>==&gt; [1] Checking Prometheus /metrics endpoint...
  [PASS] gateway_connected_clients present
  [PASS] gateway_events_per_second present
  [PASS] gateway_connections_total present

==&gt; [2] Checking JSON snapshot...
  [PASS] connectedClients in snapshot
  [PASS] eventsPerSecond in snapshot

==&gt; [3] Checking dashboard...
  [PASS] dashboard returns 200

==&gt; [4] Live metric values:
{
    "connectedClients": 50,
    "eventsPerSecond": 487.20,
    "totalConnections": 50,
    "totalDisconnections": 0,
    "totalMessageBytes": 49152,
    "connectionErrors": 0
}

==&gt; All checks complete.</code></code></pre><h3>View Raw Prometheus Output</h3><pre><code><code>curl http://localhost:8080/metrics</code></code></pre><p>Expected:</p><pre><code><code># HELP gateway_connected_clients Current number of connected WebSocket clients
# TYPE gateway_connected_clients gauge
gateway_connected_clients 50
# HELP gateway_events_per_second Sliding-window event processing rate
# TYPE gateway_events_per_second gauge
gateway_events_per_second 487.20
# HELP gateway_connections_total Total WebSocket connections accepted
# TYPE gateway_connections_total counter
gateway_connections_total 50
...
# HELP gateway_events_by_type_total Events processed broken out by type
# TYPE gateway_events_by_type_total counter
gateway_events_by_type_total{type="MESSAGE"} 9823
gateway_events_by_type_total{type="HEARTBEAT"} 3014
gateway_events_by_type_total{type="VOICE"} 1201
gateway_events_by_type_total{type="REACTION"} 962</code></code></pre><h3>Run Unit Tests</h3><pre><code><code>cd flux-gateway-observability
mvn test</code></code></pre><p>All three test classes should pass: <code>MetricsRegistryTest</code>, <code>PrometheusExporterTest</code>, <code>EventRateCalculatorTest</code>.</p><h3>VisualVM Observation</h3><ol><li><p>Open VisualVM, connect to the running <code>gateway-observability</code> process.</p></li><li><p>Under the Threads tab: you should see N carrier threads (N = CPU count) and the Virtual Thread count spiking to ~50 during the load test, then returning to baseline after the demo completes.</p></li><li><p>Under the Heap tab: the allocation rate should be near zero from the metrics layer &#8212; a flat sawtooth from normal JVM overhead, not a climbing ramp.</p></li><li><p>If you see carrier thread count growing beyond N, run <code>jcmd &lt;pid&gt; Thread.dump_to_file -format=json /tmp/td.json</code> and grep for <code>"PINNED"</code> to find the culprit.</p></li></ol><h3>Stopping and Cleanup</h3><pre><code><code>./stop.sh      # kills the running server process
./cleanup.sh   # removes target/ and build artifacts (does not kill the process)</code></code></pre><div><hr></div><h2>Homework Challenges</h2><p><strong>Beginner</strong>: Add a <code>gateway_disconnections_total</code> counter broken out by reason code (timeout, error, clean close). Expose it in the Prometheus endpoint with a <code>reason</code> label.</p><p><strong>Intermediate</strong>: Implement an HDR histogram for event processing latency. Track min/max/p50/p99 latency in nanoseconds using a simple power-of-2 bucket array (no external libraries). Expose as <code>gateway_latency_ns_bucket{le="..."}</code> in Prometheus histogram format.</p><p><strong>Expert</strong>: Replace the pull-model Prometheus endpoint with a push-model <code>PushGateway</code> client. Batch-write metrics every 5 seconds using a Virtual Thread. Handle PushGateway unavailability with an exponential backoff retry loop using <code>VarHandle</code>-based state to avoid double-sending during retries. The state machine should have states: <code>IDLE &#8594; PUSHING &#8594; RETRYING &#8594; IDLE</code>.</p>]]></content:encoded></item><item><title><![CDATA[Day 59 : Rolling Updates for Stateful WebSockets: Drain vs. Kill]]></title><description><![CDATA[The Spring Boot Trap]]></description><link>https://javatsc.substack.com/p/day-59-rolling-updates-for-stateful</link><guid isPermaLink="false">https://javatsc.substack.com/p/day-59-rolling-updates-for-stateful</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Mon, 03 Aug 2026 01:45:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!lRoK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35e7c60b-769e-4676-90c2-a48271d2f52d_1075x650.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>The Spring Boot Trap</h2><blockquote><p>A junior engineer deploying a new Gateway build does this:</p></blockquote><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;4ac52fd0-ba46-4359-957b-8b62e3548969&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">server.shutdown=graceful
spring.lifecycle.timeout-per-shutdown-phase=30s</code></pre></div><blockquote><p>They run <code>kubectl rollout restart deployment/gateway</code>, watch the pods cycle, and mark the ticket done. At 3 AM the next deploy, PagerDuty fires. Error rate spikes to 40%. The load balancer logs show 80,000 simultaneous reconnect attempts hitting two healthy nodes that were already at 70% capacity. The cascade takes four minutes to recover.</p><p>The root cause: Spring&#8217;s graceful shutdown closes the HTTP listener and waits for in-flight <em>requests</em> to complete. WebSocket connections are not requests. They are long-lived, stateful sessions. Spring closes them all simultaneously the moment the drain window expires. Every client reconnects at once. This is the reconnect storm.</p></blockquote><div><hr></div><h2>The Failure Mode: Thundering Herd on Deploy</h2><blockquote><p>At 100,000 concurrent WebSocket sessions, a simultaneous disconnect generates 100,000 TCP SYN packets within 200&#8211;400 ms. The surviving gateway nodes, already serving their own session load, must:</p><ul><li><p>Complete the TLS handshake for each new connection</p></li><li><p>Re-authenticate the session token</p></li><li><p>Re-subscribe the session to all guild pub/sub channels</p></li><li><p>Re-hydrate presence state</p></li></ul><p>Each reconnect costs roughly 8&#8211;12 ms of CPU across those steps. At 100K concurrent reconnects, that is 800,000&#8211;1,200,000 ms of CPU work arriving in under one second. Two nodes with 16 cores each have a combined capacity of roughly 32,000 ms of CPU per second. You are 25x over capacity. The nodes fall over. The load balancer marks them unhealthy. Now all reconnects hit zero nodes. Full outage.</p><p>The fix is not faster hardware. It is not more replicas. It is <em>draining sessions gracefully</em> so clients reconnect in a controlled, staggered fashion across the remaining healthy nodes.</p></blockquote><div><hr></div><h2>The Flux Architecture: Drain Coordinator</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!lRoK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35e7c60b-769e-4676-90c2-a48271d2f52d_1075x650.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!lRoK!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35e7c60b-769e-4676-90c2-a48271d2f52d_1075x650.png 424w, /__u/substackcdn.com/image/fetch/$s_!lRoK!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35e7c60b-769e-4676-90c2-a48271d2f52d_1075x650.png 848w, /__u/substackcdn.com/image/fetch/$s_!lRoK!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35e7c60b-769e-4676-90c2-a48271d2f52d_1075x650.png 1272w, /__u/substackcdn.com/image/fetch/$s_!lRoK!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35e7c60b-769e-4676-90c2-a48271d2f52d_1075x650.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!lRoK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35e7c60b-769e-4676-90c2-a48271d2f52d_1075x650.png" width="558" height="337.3953488372093" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/35e7c60b-769e-4676-90c2-a48271d2f52d_1075x650.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:650,&quot;width&quot;:1075,&quot;resizeWidth&quot;:558,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!lRoK!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35e7c60b-769e-4676-90c2-a48271d2f52d_1075x650.png 424w, /__u/substackcdn.com/image/fetch/$s_!lRoK!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35e7c60b-769e-4676-90c2-a48271d2f52d_1075x650.png 848w, /__u/substackcdn.com/image/fetch/$s_!lRoK!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35e7c60b-769e-4676-90c2-a48271d2f52d_1075x650.png 1272w, /__u/substackcdn.com/image/fetch/$s_!lRoK!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35e7c60b-769e-4676-90c2-a48271d2f52d_1075x650.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/javatsc.substack.com/p/day-59-rolling-updates-for-stateful">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Week 2: Dynamic Scheduling Foundations (Days 6–10)]]></title><description><![CDATA[Why This Matters]]></description><link>https://javatsc.substack.com/p/week-2-dynamic-scheduling-foundations</link><guid isPermaLink="false">https://javatsc.substack.com/p/week-2-dynamic-scheduling-foundations</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Sat, 01 Aug 2026 02:31:26 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!6OHs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50428e42-4a99-464e-a09d-4bf4e39f094b_1187x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Why This Matters</h2><blockquote><p>Last week, schedules lived inside Java method annotations. That is fine for a classroom demo. It collapses the moment a product manager asks, &#8220;Can we move the reconciliation job from 2 AM to 3 AM without a deploy?&#8221; Shipping a JAR for every cadence change is how early systems age into change-request queues &#8212; not how Airflow, Quartz, AWS EventBridge, or Kubernetes CronJob operators work.</p><p>Those systems treat schedules as <strong>data</strong>: durable records that operators create, pause, retarget, and audit. GitHub Actions stores workflow crons in YAML that CI can edit without recompiling runners. Stripe&#8217;s billing cycles are configuration rows, not hardcoded timers in payment workers. Chronos &#8212; this week&#8217;s project &#8212; follows the same contract: <code>TaskDefinition</code> rows in an RDBMS, a REST catalog for mutations, a dynamic binder that turns ACTIVE rows into Spring <code>ScheduledFuture</code>s, and <code>Runnable</code> / <code>Callable</code> wrappers that normalize execution into a result table.</p><p>What changes in your mental model is subtle but permanent. Scheduling stops being &#8220;a method that fires&#8221; and becomes &#8220;a write path with lifecycle.&#8221; If definitions are not durable, searchable, and activatable, nobody can answer <em>what will fire at 02:00 across the fleet</em> &#8212; which is the question on-call engineers ask when something goes wrong before sunrise.</p><p>At ultra-scale the insight sharpens: <strong>the schedule catalog is a control plane</strong>. Workers may multiply; queues may fan out; locks will come later. The catalog remains the source of truth for <em>what exists</em>. Get the model wrong now, and every later distributed feature becomes a retrofit.</p></blockquote><h2>Agenda</h2><blockquote><ol><li><p>Why static <code>@Scheduled</code> is a product bottleneck</p></li><li><p>The task definition model as a system contract</p></li><li><p>RDBMS persistence for schedules (transactions, indexes, audits)</p></li><li><p>REST catalog: CRUD plus activate / pause as lifecycle ops</p></li><li><p>Component architecture of Chronos</p></li><li><p>Dynamic binding control flow: DB &#8594; cron &#8594; execute &#8594; record</p></li><li><p>Definition and execution state machines</p></li><li><p><code>Runnable</code> vs <code>Callable</code> as execution interfaces</p></li><li><p>Fit in the 60-day distributed scheduler roadmap</p></li><li><p>Build, verify, assign, and mastery checklist</p></li></ol></blockquote><h2>Core Concepts</h2><h3>From Code Timers to Catalog Entries</h3><p>Week 1 wired triggers with <code>@Scheduled(fixedRate|fixedDelay|cron)</code>. The compiler baked intent into bytecode. Chronos inverts that: intent lands in a table, and a runtime service <em>binds</em> eligible rows to Spring&#8217;s <code>TaskScheduler</code>.</p><p>Think of the difference between a playlist burned onto a CD versus a streaming library. The CD cannot change mid-flight; the library can. Production ops teams need the library. Redeploys become risk events &#8212; configuration changes should not require them.</p><p>The non-obvious implication for system design: <strong>create/update is now part of the scheduling surface</strong>. Validation, uniqueness, and state transitions belong in services &#8212; not only &#8220;does the cron fire.&#8221; Invalid cron on activate must fail loudly before a ghost <code>ScheduledFuture</code> exists with no matching row.</p><h3>Definitions Are Contracts</h3><p>A <code>TaskDefinition</code> answers four operational questions:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!W-jH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81a88b1-335f-4724-a174-c47eaf318d8e_1026x411.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!W-jH!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81a88b1-335f-4724-a174-c47eaf318d8e_1026x411.png 424w, /__u/substackcdn.com/image/fetch/$s_!W-jH!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81a88b1-335f-4724-a174-c47eaf318d8e_1026x411.png 848w, /__u/substackcdn.com/image/fetch/$s_!W-jH!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81a88b1-335f-4724-a174-c47eaf318d8e_1026x411.png 1272w, /__u/substackcdn.com/image/fetch/$s_!W-jH!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81a88b1-335f-4724-a174-c47eaf318d8e_1026x411.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!W-jH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81a88b1-335f-4724-a174-c47eaf318d8e_1026x411.png" width="638" height="255.57309941520467" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d81a88b1-335f-4724-a174-c47eaf318d8e_1026x411.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:411,&quot;width&quot;:1026,&quot;resizeWidth&quot;:638,&quot;bytes&quot;:48270,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://javatsc.substack.com/i/206985165?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81a88b1-335f-4724-a174-c47eaf318d8e_1026x411.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!W-jH!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81a88b1-335f-4724-a174-c47eaf318d8e_1026x411.png 424w, /__u/substackcdn.com/image/fetch/$s_!W-jH!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81a88b1-335f-4724-a174-c47eaf318d8e_1026x411.png 848w, /__u/substackcdn.com/image/fetch/$s_!W-jH!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81a88b1-335f-4724-a174-c47eaf318d8e_1026x411.png 1272w, /__u/substackcdn.com/image/fetch/$s_!W-jH!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81a88b1-335f-4724-a174-c47eaf318d8e_1026x411.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/javatsc.substack.com/p/week-2-dynamic-scheduling-foundations">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 58: Sync Engine — Reconciling a Stale Client After Reconnection]]></title><description><![CDATA[The Spring Boot Trap]]></description><link>https://javatsc.substack.com/p/day-58-sync-engine-reconciling-a</link><guid isPermaLink="false">https://javatsc.substack.com/p/day-58-sync-engine-reconciling-a</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Fri, 31 Jul 2026 01:45:24 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!XcTL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a362ee5-ba5f-40aa-b6f0-2475713c1791_1125x675.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>The Spring Boot Trap</h2><blockquote><p>A junior engineer writes this:</p></blockquote><pre><code><code>List&lt;Event&gt; missed = eventRepo.findByGuildIdAndTimestampAfter(guildId, session.lastSeen());
socket.send(objectMapper.writeValueAsBytes(missed));</code></code></pre><blockquote><p>It works in staging with five users. It catastrophically fails when 400,000 mobile clients reconnect after a 20-minute outage &#8212; the scenario Discord engineers call a &#8220;reconnect storm.&#8221;</p><p>The hidden costs: <code>findByGuildIdAndTimestampAfter</code> does a full index scan with no upper bound. At 100 missed events per client, you are deserializing 40 million <code>Event</code> objects simultaneously. The Eden space fills in seconds. The JVM fires stop-the-world GC collections lasting 800ms each, exactly while the thread pool is already saturated processing reconnects. The database connection pool exhausts. The entire Gateway pod crashes and takes its neighbors with it via a cascading failure.</p><p>The framework hid every one of those failure modes behind a clean repository interface.</p></blockquote><h2>The Failure Mode: Unbounded Delta Fetching</h2><blockquote><p>The naive sync strategy has three structural flaws:</p><p><strong>No upper bound on delta size.</strong> A client offline for six hours in a busy guild has missed tens of thousands of events. Materializing all of them into heap memory is an OOM waiting to happen.</p><p><strong>No event prioritization.</strong> Presence changes, role updates, and membership events affect what the client can render. Dumping chat messages on top of them means the client shows a broken UI while waiting for structural data to arrive.</p><p><strong>No cursor continuity.</strong> Using wall-clock timestamps for sync is incorrect. Clocks drift. Events written within the same millisecond have undefined ordering under <code>timestamp &gt;= ?</code>. You need a monotonic sequence number, not a timestamp.</p></blockquote><h2>The Flux Architecture: Three-Phase Cursor Sync</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!XcTL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a362ee5-ba5f-40aa-b6f0-2475713c1791_1125x675.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!XcTL!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a362ee5-ba5f-40aa-b6f0-2475713c1791_1125x675.png 424w, /__u/substackcdn.com/image/fetch/$s_!XcTL!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a362ee5-ba5f-40aa-b6f0-2475713c1791_1125x675.png 848w, /__u/substackcdn.com/image/fetch/$s_!XcTL!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a362ee5-ba5f-40aa-b6f0-2475713c1791_1125x675.png 1272w, /__u/substackcdn.com/image/fetch/$s_!XcTL!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a362ee5-ba5f-40aa-b6f0-2475713c1791_1125x675.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!XcTL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a362ee5-ba5f-40aa-b6f0-2475713c1791_1125x675.png" width="528" height="316.8" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5a362ee5-ba5f-40aa-b6f0-2475713c1791_1125x675.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:675,&quot;width&quot;:1125,&quot;resizeWidth&quot;:528,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!XcTL!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a362ee5-ba5f-40aa-b6f0-2475713c1791_1125x675.png 424w, /__u/substackcdn.com/image/fetch/$s_!XcTL!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a362ee5-ba5f-40aa-b6f0-2475713c1791_1125x675.png 848w, /__u/substackcdn.com/image/fetch/$s_!XcTL!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a362ee5-ba5f-40aa-b6f0-2475713c1791_1125x675.png 1272w, /__u/substackcdn.com/image/fetch/$s_!XcTL!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a362ee5-ba5f-40aa-b6f0-2475713c1791_1125x675.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/javatsc.substack.com/p/day-58-sync-engine-reconciling-a">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 57: Client-Side Cache :Building a Local SQLite Store for Offline-First Clients]]></title><description><![CDATA[What You Will Build]]></description><link>https://javatsc.substack.com/p/day-57-client-side-cache-building</link><guid isPermaLink="false">https://javatsc.substack.com/p/day-57-client-side-cache-building</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Tue, 28 Jul 2026 01:45:15 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!2il9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb819487b-b5c3-40e2-a044-a194c7ca1389_1075x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>What You Will Build</h3><blockquote><ul><li><p>A write-through SQLite cache that persists every Gateway event to disk before the UI renders it.</p></li><li><p>A cursor-based delta sync protocol: on reconnect, the client sends its last-seen message ID per channel and receives only the diff.</p></li><li><p>Dirty-write tracking with optimistic UI updates and server-ACK reconciliation.</p></li><li><p>A real-time dashboard showing cache hit rate, dirty row backlog, sync lag, and per-channel cursors.</p></li></ul></blockquote><div><hr></div><h2>1. The Junior Engineer&#8217;s Trap</h2><p>A junior Discord clone engineer writes this on reconnect:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;6adbd7c5-1362-4295-b595-27409788de2e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">void onReconnect() {
    List&lt;Message&gt; messages = restClient.fetchMessages(channelId, limit=50);
    List&lt;Guild&gt;   guilds   = restClient.fetchGuilds();
    ui.render(messages, guilds);
}</code></pre></div><blockquote><p>It works in development. Then your service has a four-minute outage. It comes back up. Every one of your two million connected clients executes those REST calls simultaneously. Your API servers collapse under a thundering herd. You have traded one outage for two.</p><p>The second problem: the UI is blank during reconnect. Users see a spinner. Discord never shows a spinner on reconnect &#8212; they see their last known state instantly because it was cached locally. That is not magic. That is engineering.</p></blockquote><div><hr></div><h2>2. The Failure Mode</h2><p>Without a local cache, three distinct failure modes hit you at scale.</p><h3>Thundering Herd on Reconnect</h3><p>When the Gateway cluster recovers after a partition, every client simultaneously requests full state from the REST tier. A two-million-user guild server can generate 40 million API calls in under 30 seconds. No horizontal scaling saves you from that spike shape &#8212; you cannot provision for a vertical cliff.</p><p> &lt;!-- IMAGE: thundering-herd-diagram.svg &#8212; Reconnect storm spike (naive) vs. cache-first flat request curve (production) --&gt; </p><h3>Perceived Latency on Cold Start</h3><p>Cold-start clients must wait for network round-trips before rendering anything. On mobile, that is 300&#8211;800ms of blank screen &#8212; enough for users to assume the app is broken and force-quit. Each force-quit generates another reconnect, compounding the herd.</p><h3>Wasted Bandwidth</h3><p>Fetching 50 messages per channel on every reconnect, when 48 of them have not changed, is pure waste. At Discord&#8217;s scale that becomes petabytes of redundant transfer per day, directly inflating infrastructure cost.</p><div><hr></div><h2>3. The Flux Architecture: Write-Through Cache with Delta Sync</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!2il9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb819487b-b5c3-40e2-a044-a194c7ca1389_1075x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!2il9!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb819487b-b5c3-40e2-a044-a194c7ca1389_1075x600.png 424w, /__u/substackcdn.com/image/fetch/$s_!2il9!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb819487b-b5c3-40e2-a044-a194c7ca1389_1075x600.png 848w, /__u/substackcdn.com/image/fetch/$s_!2il9!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb819487b-b5c3-40e2-a044-a194c7ca1389_1075x600.png 1272w, /__u/substackcdn.com/image/fetch/$s_!2il9!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb819487b-b5c3-40e2-a044-a194c7ca1389_1075x600.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!2il9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb819487b-b5c3-40e2-a044-a194c7ca1389_1075x600.png" width="566" height="315.90697674418607" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b819487b-b5c3-40e2-a044-a194c7ca1389_1075x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:1075,&quot;resizeWidth&quot;:566,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!2il9!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb819487b-b5c3-40e2-a044-a194c7ca1389_1075x600.png 424w, /__u/substackcdn.com/image/fetch/$s_!2il9!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb819487b-b5c3-40e2-a044-a194c7ca1389_1075x600.png 848w, /__u/substackcdn.com/image/fetch/$s_!2il9!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb819487b-b5c3-40e2-a044-a194c7ca1389_1075x600.png 1272w, /__u/substackcdn.com/image/fetch/$s_!2il9!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb819487b-b5c3-40e2-a044-a194c7ca1389_1075x600.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/javatsc.substack.com/p/day-57-client-side-cache-building">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Week 1: Spring Scheduling Fundamentals (Days 1–5) ]]></title><description><![CDATA[Why This Matters]]></description><link>https://javatsc.substack.com/p/week-1-spring-scheduling-fundamentals</link><guid isPermaLink="false">https://javatsc.substack.com/p/week-1-spring-scheduling-fundamentals</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Sun, 26 Jul 2026 08:30:37 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!D4pz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F206cd7cd-ee62-4e0d-b8cc-2ffef66c74ac_1187x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Why This Matters</h2><blockquote><p>Every system that processes payments overnight, sends digest emails, or refreshes a product catalog depends on a scheduler. Netflix pushes encoding jobs on cron. Uber reconciles ride fares in batch windows. Your phone backs up photos on a fixed interval. The pattern is identical: <em>something must fire at the right time, reliably, without human intervention.</em></p><p>Spring Boot ships with scheduling built in &#8212; but built in for <strong>one machine</strong>. This lesson establishes the foundation layer you will extend across 60 days: heartbeat monitoring, trigger patterns, thread pools, cluster duplication awareness, and the blueprint for a production distributed scheduler.</p><p>What makes scheduling a system design problem &#8212; not just a coding convenience &#8212; is that time itself becomes shared infrastructure. A bug in your REST API might affect one request. A bug in your scheduler can charge ten thousand customers twice, send duplicate emails to every user, or leave stale inventory on a storefront for hours.</p></blockquote><h2>Agenda</h2><blockquote><ol><li><p>What task scheduling is and where it lives in system design</p></li><li><p>Component architecture of the Scheduler Foundation control plane</p></li><li><p>Spring&#8217;s <code>@Scheduled</code> trigger modes: fixedRate, fixedDelay, cron</p></li><li><p>Thread pool customization with <code>ThreadPoolTaskScheduler</code></p></li><li><p>Task execution control flow &#8212; from trigger to metrics</p></li><li><p>Scheduled task lifecycle and state transitions</p></li><li><p>The multi-instance duplication problem</p></li><li><p>Target architecture for a distributed scheduler</p></li></ol></blockquote><h2>Core Concepts</h2><h3>Scheduling as a Control Plane</h3><p>Think of a scheduler as an <strong>operating system for time</strong>. Application code declares <em>what</em> should run and <em>when</em>; the scheduler decides <em>how</em> to dispatch work onto threads. In Spring, <code>@EnableScheduling</code> activates a background registrar that scans beans for <code>@Scheduled</code> methods and registers triggers against an internal <code>TaskScheduler</code>.</p><p>Three trigger semantics matter:</p><p><strong>ModeFiresReal-world usefixedRate</strong>Every N ms from startHeartbeats, health probes<strong>fixedDelay</strong>N ms after previous finishCleanup that must not overlap<strong>cron</strong>Calendar expressionReports at 2 AM, invoice cycles</p><p>The distinction is subtle but consequential. <strong>fixedRate</strong> measures from the <em>start</em> of each interval &#8212; if a task runs long, the next invocation may queue up immediately after it finishes, potentially stacking executions. <strong>fixedDelay</strong> waits until the task <em>completes</em>, then starts the countdown &#8212; ideal when overlapping runs would corrupt shared state. <strong>cron</strong> expresses calendar intent: &#8220;every Monday at 03:00 UTC,&#8221; which is how billing cycles and compliance reports are defined in production.</p><p>Stripe&#8217;s reconciliation jobs use cron-like windows. Datadog agents use fixedRate heartbeats. Log compaction in Kafka uses fixedDelay so a slow run does not stack.</p><h3>Thread Pools Are Throughput Levers</h3><p>By default, Spring uses a <strong>single-thread</strong> scheduler. One slow task blocks everything else &#8212; unacceptable at scale. <code>ThreadPoolTaskScheduler</code> with a custom pool (10 core, 20 max in our project) lets concurrent tasks run in parallel. Wiring it through <code>SchedulingConfigurer</code> replaces the default registrar &#8212; the same pattern used inside large e-commerce flash-sale engines where hundreds of micro-tasks fire per second.</p><p>Without a pool, your health probe waits while a report generation task holds the only thread for thirty seconds. With a pool, each scheduled method gets its own worker when the trigger fires. The trade-off: more threads mean more memory and more concurrent access to shared resources &#8212; which is exactly why Week 3 introduces distributed locks.</p><h3>The Duplication Trap</h3><p>Deploy two instances behind a load balancer and every <code>@Scheduled</code> method runs <strong>twice</strong>. No shared state, no coordination. Instance A and Instance B both charge customers, both generate reports. Our cluster simulation launches two JVMs with distinct instance IDs, persists executions to H2, and surfaces duplicate counts on the dashboard &#8212; the same failure mode that burned teams at early-stage fintech startups before they added distributed locks.</p><p>This is not a Spring bug. It is the correct behavior of independent clocks. Each JVM has its own scheduler thread, its own trigger registry, and zero awareness of peer nodes. The fix &#8212; leader election, distributed locks, or message-queue handoff &#8212; comes in later weeks. Week 1 makes the problem visible so you never forget it exists.</p><h2>Component Architecture</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!D4pz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F206cd7cd-ee62-4e0d-b8cc-2ffef66c74ac_1187x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!D4pz!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F206cd7cd-ee62-4e0d-b8cc-2ffef66c74ac_1187x600.png 424w, /__u/substackcdn.com/image/fetch/$s_!D4pz!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F206cd7cd-ee62-4e0d-b8cc-2ffef66c74ac_1187x600.png 848w, /__u/substackcdn.com/image/fetch/$s_!D4pz!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F206cd7cd-ee62-4e0d-b8cc-2ffef66c74ac_1187x600.png 1272w, /__u/substackcdn.com/image/fetch/$s_!D4pz!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F206cd7cd-ee62-4e0d-b8cc-2ffef66c74ac_1187x600.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!D4pz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F206cd7cd-ee62-4e0d-b8cc-2ffef66c74ac_1187x600.png" width="556" height="281.044650379107" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/206cd7cd-ee62-4e0d-b8cc-2ffef66c74ac_1187x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:1187,&quot;resizeWidth&quot;:556,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!D4pz!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F206cd7cd-ee62-4e0d-b8cc-2ffef66c74ac_1187x600.png 424w, /__u/substackcdn.com/image/fetch/$s_!D4pz!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F206cd7cd-ee62-4e0d-b8cc-2ffef66c74ac_1187x600.png 848w, /__u/substackcdn.com/image/fetch/$s_!D4pz!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F206cd7cd-ee62-4e0d-b8cc-2ffef66c74ac_1187x600.png 1272w, /__u/substackcdn.com/image/fetch/$s_!D4pz!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F206cd7cd-ee62-4e0d-b8cc-2ffef66c74ac_1187x600.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>UI / API layer :</strong> sit at the top &#8212; the human-facing and programmatic entry points:</p><ul><li><p><strong>Dashboard</strong> &#8212; the live web UI where operators watch heartbeats, thread utilization, duplicate counts, and the architecture roadmap. In production systems like Airflow or Temporal, this role is filled by a web console; here it is a lightweight Thymeleaf dashboard.</p></li><li><p><strong>REST API</strong> &#8212; programmatic access to the same data. Other services, CI pipelines, or monitoring tools call these endpoints without loading the UI.</p></li><li><p><strong>Task Registry</strong> &#8212; an in-memory catalog of task definitions (name, trigger type, expression, lifecycle). In Week 2 this moves to a persistent database; the box is already positioned where that upgrade lands.</p></li></ul><p><strong>Runtime layer </strong>do the actual work:</p><ul><li><p><strong>Thread Pool</strong> &#8212; the worker fleet inside a single JVM. When a trigger fires, the pool assigns a thread. Pool size directly caps how many scheduled tasks can run simultaneously on one node.</p></li><li><p><strong>Scheduler Core</strong> &#8212; the brain. It hosts <code>@Scheduled</code> method registration, trigger evaluation, and dispatch to the thread pool. Everything time-related flows through here.</p></li><li><p><strong>Execution Store</strong> &#8212; the audit trail. Every cluster-mode run is persisted with instance ID, timestamp, status, and details. This is your forensic log when duplicates appear.</p></li></ul><p><strong>Future layer</strong>:</p><ul><li><p><strong>Lock Service</strong> &#8212; not implemented yet, deliberately shown with a dashed border. In Weeks 3&#8211;4 you will add Redis- or database-backed locks so only one instance executes a given task tick. The arrow from Instance B toward Lock Service hints at the coordination path both nodes will eventually use.</p></li></ul><p><strong>Instance A and Instance B</strong> at the bottom represent horizontally scaled deployments. Both connect upward to Scheduler Core independently &#8212; that is the duplication problem visualized. In a corrected architecture, Lock Service sits between instances and execution, gating who may proceed.</p><h2>Task Execution Control Flow</h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!hHmz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35b7435c-7e87-4ab6-b7c8-4d8ca15aac64_1125x437.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!hHmz!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35b7435c-7e87-4ab6-b7c8-4d8ca15aac64_1125x437.png 424w, /__u/substackcdn.com/image/fetch/$s_!hHmz!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35b7435c-7e87-4ab6-b7c8-4d8ca15aac64_1125x437.png 848w, /__u/substackcdn.com/image/fetch/$s_!hHmz!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35b7435c-7e87-4ab6-b7c8-4d8ca15aac64_1125x437.png 1272w, /__u/substackcdn.com/image/fetch/$s_!hHmz!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35b7435c-7e87-4ab6-b7c8-4d8ca15aac64_1125x437.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!hHmz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35b7435c-7e87-4ab6-b7c8-4d8ca15aac64_1125x437.png" width="594" height="230.736" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/35b7435c-7e87-4ab6-b7c8-4d8ca15aac64_1125x437.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:437,&quot;width&quot;:1125,&quot;resizeWidth&quot;:594,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!hHmz!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35b7435c-7e87-4ab6-b7c8-4d8ca15aac64_1125x437.png 424w, /__u/substackcdn.com/image/fetch/$s_!hHmz!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35b7435c-7e87-4ab6-b7c8-4d8ca15aac64_1125x437.png 848w, /__u/substackcdn.com/image/fetch/$s_!hHmz!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35b7435c-7e87-4ab6-b7c8-4d8ca15aac64_1125x437.png 1272w, /__u/substackcdn.com/image/fetch/$s_!hHmz!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35b7435c-7e87-4ab6-b7c8-4d8ca15aac64_1125x437.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This flowchart traces what happens from the moment a trigger fires until metrics appear on the dashboard.</p><h3>Step-by-step walkthrough</h3><ul><li><p><strong>Trigger</strong> &#8212; the starting event. A clock tick (<code>fixedRate</code>), a completion delay (<code>fixedDelay</code>), or a cron match initiates the pipeline. Nothing runs yet; the scheduler has simply decided <em>now is the time</em>.</p></li><li><p><strong>Timer &#8594; Thread Pool &#8594; Execute</strong> &#8212; the horizontal chain across the top is the happy path on a single node. The timer hands off to the pool, the pool assigns a worker thread, and the <code>@Scheduled</code> method body runs. If the pool is saturated, tasks queue inside the pool &#8212; visible on the dashboard as rising active thread counts.</p></li><li><p><strong>Multi? (decision diamond)</strong> &#8212; the critical fork. After execution completes, the system asks: <em>are multiple instances running?</em> On a single JVM the answer is no, and the flow proceeds straight to <strong>Persist Log</strong>. In cluster mode the answer is yes &#8212; and without a lock, both instances took the execute path independently.</p></li><li><p><strong>Duplicate Run </strong>&#8212; the failure branch. When two instances fire the same trigger, both reach Execute. Neither knows the other ran. Billing runs twice. Reports generate twice. This box exists because Week 1 intentionally omits the lock that would block this path.</p></li><li><p><strong>Persist Log &#8594; Metrics</strong> &#8212; regardless of duplication, each execution is recorded in the Execution Store and surfaced as dashboard metrics and Prometheus counters. This is why the cluster simulation panel can count duplicates: the log captures <em>who</em> ran <em>what</em>, even when coordination is missing.</p></li></ul><h2>Scheduled Task Lifecycle</h2><p>Every scheduled task moves through a finite set of states. Understanding this machine is prerequisite to adding retries, timeouts, and idempotency in later lessons.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!fzhN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bb31413-3203-4c9f-9846-400ec06738b4_1062x500.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!fzhN!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bb31413-3203-4c9f-9846-400ec06738b4_1062x500.png 424w, /__u/substackcdn.com/image/fetch/$s_!fzhN!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bb31413-3203-4c9f-9846-400ec06738b4_1062x500.png 848w, /__u/substackcdn.com/image/fetch/$s_!fzhN!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bb31413-3203-4c9f-9846-400ec06738b4_1062x500.png 1272w, /__u/substackcdn.com/image/fetch/$s_!fzhN!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bb31413-3203-4c9f-9846-400ec06738b4_1062x500.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!fzhN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bb31413-3203-4c9f-9846-400ec06738b4_1062x500.png" width="500" height="235.40489642184556" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5bb31413-3203-4c9f-9846-400ec06738b4_1062x500.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:1062,&quot;resizeWidth&quot;:500,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!fzhN!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bb31413-3203-4c9f-9846-400ec06738b4_1062x500.png 424w, /__u/substackcdn.com/image/fetch/$s_!fzhN!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bb31413-3203-4c9f-9846-400ec06738b4_1062x500.png 848w, /__u/substackcdn.com/image/fetch/$s_!fzhN!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bb31413-3203-4c9f-9846-400ec06738b4_1062x500.png 1272w, /__u/substackcdn.com/image/fetch/$s_!fzhN!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bb31413-3203-4c9f-9846-400ec06738b4_1062x500.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>States explained</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!FYXz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b3d4ed3-018e-4dbf-bfcc-da0a988dc43c_912x361.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!FYXz!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b3d4ed3-018e-4dbf-bfcc-da0a988dc43c_912x361.png 424w, /__u/substackcdn.com/image/fetch/$s_!FYXz!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b3d4ed3-018e-4dbf-bfcc-da0a988dc43c_912x361.png 848w, /__u/substackcdn.com/image/fetch/$s_!FYXz!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b3d4ed3-018e-4dbf-bfcc-da0a988dc43c_912x361.png 1272w, /__u/substackcdn.com/image/fetch/$s_!FYXz!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b3d4ed3-018e-4dbf-bfcc-da0a988dc43c_912x361.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!FYXz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b3d4ed3-018e-4dbf-bfcc-da0a988dc43c_912x361.png" width="912" height="361" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9b3d4ed3-018e-4dbf-bfcc-da0a988dc43c_912x361.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:361,&quot;width&quot;:912,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:50024,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://javatsc.substack.com/i/206965790?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b3d4ed3-018e-4dbf-bfcc-da0a988dc43c_912x361.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!FYXz!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b3d4ed3-018e-4dbf-bfcc-da0a988dc43c_912x361.png 424w, /__u/substackcdn.com/image/fetch/$s_!FYXz!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b3d4ed3-018e-4dbf-bfcc-da0a988dc43c_912x361.png 848w, /__u/substackcdn.com/image/fetch/$s_!FYXz!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b3d4ed3-018e-4dbf-bfcc-da0a988dc43c_912x361.png 1272w, /__u/substackcdn.com/image/fetch/$s_!FYXz!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b3d4ed3-018e-4dbf-bfcc-da0a988dc43c_912x361.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4><span>Transitions</span></h4><ul><li><p><strong>tick</strong> (IDLE &#8594; SCHEDULED): the trigger fires. For <code>fixedRate</code>, this happens on a wall-clock interval regardless of previous run duration. For <code>fixedDelay</code>, it happens N milliseconds after the last run <em>finished</em>.</p></li><li><p><strong>dispatch</strong> (SCHEDULED &#8594; RUNNING): the thread pool assigns a worker. If the pool is full, SCHEDULED persists until a thread frees up &#8212; this is backpressure at the scheduling layer.</p></li><li><p><strong>done</strong> (RUNNING &#8594; SUCCESS): clean completion. The task returns to IDLE via the dashed retry/next-cycle path, ready for the next trigger.</p></li><li><p><strong>error</strong> (RUNNING &#8594; FAILED): uncaught exception or resource exhaustion. FAILED can transition to FAILED again on repeated errors (the vertical arrow between SUCCESS and FAILED represents monitoring overlap &#8212; a task that succeeded once can fail on the next cycle).</p></li></ul><h3>Pool Queue</h3><p>The green <strong>Pool Queue</strong> box connected to RUNNING represents tasks waiting for threads when the pool is saturated. In our project with six concurrent pool workloads plus three core scheduler tasks, you will see this queue activity on the Thread Pool dashboard panel during high-frequency bursts.</p><h3>Why this matters at scale</h3><p>Production schedulers at companies like Shopify and LinkedIn treat state as a first-class database column, not an in-memory afterthought. When you can query &#8220;show me all tasks stuck in RUNNING for more than 10 minutes,&#8221; you have operability. This state machine is the conceptual foundation for that capability.</p><h2>Key Code Snippets</h2><p><strong>Enable scheduling and custom pool:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;590e567f-056c-4adb-b9e6-25d9e667d787&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">@SpringBootApplication
@EnableScheduling
public class SchedulerFoundationApplication { ... }

@Configuration
public class FoundationSchedulingConfigurer implements SchedulingConfigurer {
    public void configureTasks(ScheduledTaskRegistrar registrar) {
        registrar.setScheduler(primaryTaskScheduler);
    }
}</code></pre></div><p><strong>Three trigger types in one service:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;2bc8ce01-4da8-4c6d-b52d-84e66f1e8552&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">@Scheduled(fixedRate = 5000)
public void healthProbe() { ... }

@Scheduled(fixedDelay = 15000)
public void resourceCleanup() { ... }

@Scheduled(cron = "0 * * * * ?")
public void periodicReport() { ... }</code></pre></div><p><strong>Instance identity for cluster observability:</strong></p><pre><code><code>app:
  instance:
    id: ${INSTANCE_ID:node-local}</code></code></pre><p>Each JVM sets <code>INSTANCE_ID</code> differently in cluster mode so the Execution Store can attribute duplicates to specific nodes.</p><div><hr></div><h2>Implementation Guide </h2><h3>GitHub Link :</h3><p><a href="https://github.com/sysdr/taskscheduler-p/tree/main/week1/scheduler-foundation">https://github.com/sysdr/taskscheduler-p/tree/main/week1/scheduler-foundation</a></p><h3>Prerequisites</h3><p><strong>ToolVersion</strong>Java21+Maven3.9+curlany recentDocker + Composeoptional (cluster demo via containers)</p><p>Verify:</p><pre><code><code>java -version    # should show 21+
mvn -version
curl --version</code></code></pre><h3>Phase 1 &#8212; Project Setup</h3><h3>1.1 Generate the project</h3><pre><code><code>cd scheduler-foundation</code></code></pre><h3>Phase 2 &#8212; Build &amp; Test</h3><h3>2.1 Compile and run tests</h3><pre><code><code>./build.sh all</code></code></pre><p><strong>Success criteria:</strong></p><ul><li><p>JAR created: <code>target/scheduler-foundation-1.0.0.jar</code></p></li><li><p>7 tests pass (1 context + 6 integration)</p></li></ul><h3>Phase 3 &#8212; Run the Application</h3><h3>3.1 One-command demo (recommended first run)</h3><pre><code><code>./demo.sh</code></code></pre><p>This will: stop old instances &#8594; build &#8594; test &#8594; start on port 8080 &#8594; wait 15s &#8594; verify APIs.</p><p>Open: http://localhost:8080/</p><h3>3.2 Manual start modes</h3><pre><code><code>./start.sh single     # one JVM on :8080
./start.sh cluster    # two JVMs on :8080 and :8081
./start.sh docker     # two containers (requires Docker Desktop + WSL integration)</code></code></pre><h3>3.3 Stop and clean up</h3><pre><code><code>./stop.sh             # stop JVM + docker compose
./cleanup.sh          # stop + remove target/, logs/, data/, Docker image
./cleanup.sh --deep   # also prune unused Docker cache</code></code></pre><h3>Phase 4 &#8212; Verify Each Feature</h3><p>Work through the dashboard panels left-to-right. Refresh is automatic every 3 seconds.</p><h3>4.1 Heartbeat (Overview + Heartbeat panel)</h3><p><strong>What it proves:</strong> The scheduler thread is alive.</p><pre><code><code>curl -s http://localhost:8080/api/heartbeat | python3 -m json.tool</code></code></pre><p>Expected fields: <code>executions</code> (increments), <code>elapsedSeconds</code>, <code>intervalMs</code> (10000).</p><p><strong>Source:</strong> <code>HeartbeatSchedulerService.java</code> &#8212; <code>@Scheduled(fixedRateString = "${scheduler.heartbeat.interval-ms}")</code></p><h3>4.2 Scheduling Patterns (fixedRate / fixedDelay / cron)</h3><p><strong>What it proves:</strong> All three Spring trigger types work independently.</p><p><strong>TaskTriggerInterval</strong>Health ProbefixedRate5sResource CleanupfixedDelay15s after completionPeriodic Reportcronevery minute</p><pre><code><code>curl -s http://localhost:8080/api/dashboard | python3 -c 
  "import sys,json; d=json.load(sys.stdin); print(d['coreScheduler'])"</code></code></pre><p><strong>Source:</strong> <code>CoreSchedulerService.java</code></p><h3>4.3 Thread Pool (Thread Pool panel)</h3><p><strong>What it proves:</strong> Custom pool handles concurrent scheduled tasks.</p><pre><code><code>curl -s http://localhost:8080/api/thread-pool | python3 -m json.tool</code></code></pre><p>Watch <code>activeThreads</code>, <code>completedTasks</code>, and the doughnut chart on the dashboard.</p><p><strong>Sources:</strong></p><ul><li><p><code>SchedulerConfig.java</code> &#8212; defines <code>primaryTaskScheduler</code> bean</p></li><li><p><code>FoundationSchedulingConfigurer.java</code> &#8212; wires pool to all <code>@Scheduled</code> tasks</p></li><li><p><code>PoolWorkloadService.java</code> &#8212; 6 concurrent workloads at different rates</p></li></ul><p>Key config in <code>application.yml</code>:</p><pre><code><code>scheduler:
  pool:
    size: 10
    max-size: 20
    thread-name-prefix: scheduler-pool-</code></code></pre><h3>4.4 Cluster Simulation (duplicate executions)</h3><p><strong>What it proves:</strong> <code>@Scheduled</code> on multiple instances = duplicate runs.</p><pre><code><code>./stop.sh
./start.sh cluster</code></code></pre><p>Open both: http://localhost:8080/ and http://localhost:8081/</p><p>Wait 2&#8211;3 minutes, then:</p><pre><code><code>curl -s http://localhost:8080/api/cluster/status | python3 -m json.tool</code></code></pre><p><strong>Expected:</strong> <code>duplicateCounts</code> shows counts &gt; 1 per task when both nodes are running.</p><p><strong>Sources:</strong></p><ul><li><p><code>ClusterScheduledService.java</code> &#8212; report (cron), billing (fixedRate), cleanup (fixedDelay)</p></li><li><p><code>ClusterExecution.java</code> + <code>ClusterExecutionRepository.java</code> &#8212; persisted audit log</p></li><li><p>Instance ID via <code>INSTANCE_ID</code> env var / <code>app.instance.id</code> in config</p></li></ul><h3>4.5 Target Architecture (blueprint panel)</h3><p><strong>What it proves:</strong> Roadmap from single-node scheduler to distributed system.</p><pre><code><code>curl -s http://localhost:8080/api/architecture | python3 -m json.tool</code></code></pre><p><strong>Expected:</strong> 7 components (3 CURRENT, 4 PLANNED) + <code>roadmap.currentCapabilities</code> / <code>nextCapabilities</code>.</p><p><strong>Source:</strong> <code>ArchitectureBlueprintService.java</code></p><h3>4.6 Task Registry API</h3><pre><code><code>curl -s http://localhost:8080/api/tasks | python3 -m json.tool
curl -s http://localhost:8080/api/tasks/statistics | python3 -m json.tool</code></code></pre><p><strong>Source:</strong> <code>TaskRegistryService.java</code>, <code>TaskRegistryController.java</code></p><h3>4.7 Prometheus metrics</h3><pre><code><code>curl -s http://localhost:8080/actuator/prometheus | head -20
curl -s http://localhost:8080/actuator/health
curl -s http://localhost:8080/actuator/scheduledtasks</code></code></pre><h2>Phase 5 &#8212; Docker Cluster (Optional)</h2><p>Requires Docker Desktop with WSL2 integration enabled.</p><pre><code><code>./cleanup.sh
./start.sh docker</code></code></pre><p><strong>Images used (official Docker Hub):</strong></p><ul><li><p>Build stage: <code>maven:3.9.9-eclipse-temurin-21</code></p></li><li><p>Runtime: <code>eclipse-temurin:21-jre-jammy</code></p></li></ul><p>Both containers share volume <code>scheduler-data</code> so H2 executions aggregate.</p><p>Verify:</p><pre><code><code>docker ps
curl http://localhost:8080/actuator/health
curl http://localhost:8081/actuator/health</code></code></pre><h2>Completion Checklist</h2><ul><li><p><code>./build.sh all</code> &#8212; 7 tests green</p></li><li><p><code>./demo.sh</code> &#8212; dashboard loads at http://localhost:8080/</p></li><li><p>Heartbeat counter increments every 10s</p></li><li><p>Scheduling Patterns panel shows all three trigger types firing</p></li><li><p>Thread Pool chart shows active vs idle threads</p></li><li><p><code>./start.sh cluster</code> &#8212; duplicate counts appear in Cluster Simulation</p></li><li><p>Architecture panel shows 7 components + roadmap</p></li><li><p><code>./cleanup.sh</code> removes runtime artifacts cleanly</p></li></ul><h3>Working Demo Link :</h3><div id="youtube2-JNQQ9uluOjo" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;JNQQ9uluOjo&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/JNQQ9uluOjo?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h2>What&#8217;s Next Preview</h2><p>Week 1 uses <strong>static</strong> <code>@Scheduled</code> annotations. Week 2 introduces:</p><ul><li><p><code>TaskDefinition</code> entity persisted in a database</p></li><li><p>REST API for dynamic task CRUD</p></li><li><p>Runtime scheduling from stored definitions (not hard-coded annotations)</p></li></ul><p>The dashboard shell and architecture blueprint you built this week carry forward unchanged.</p><h2>Quick Command Reference</h2><pre><code><code> cd scheduler-foundation

# Develop cycle
./build.sh all          # compile + test
./demo.sh               # full demo
./start.sh single       # run
./stop.sh               # stop

# Cluster demo
./start.sh cluster

# Docker demo
./start.sh docker

# Cleanup
./cleanup.sh
./cleanup.sh --deep</code></code></pre><h2>Assignment</h2><ol><li><p>Add a fourth scheduled task using a cron expression that fires every 30 seconds. Register it in the task registry API.</p></li><li><p>Change the thread pool size to 5 and observe how <code>highFrequencyPulse</code> execution latency shifts on the dashboard.</p></li><li><p>Launch cluster mode and record how many <code>BILLING_CYCLE</code> executions occur in 3 minutes with two instances. Calculate the duplication factor.</p></li><li><p>Sketch (on paper or in the architecture panel) where a <strong>Lock Service</strong> would sit between the Scheduler Core and Worker Tasks.</p></li></ol><h3>Solution Hints</h3><ol><li><p>Add <code>@Scheduled(cron = "0/30 * * * * *")</code> in <code>PoolWorkloadService</code> or a new bean; POST a matching entry via <code>/api/tasks</code>.</p></li><li><p>Set <code>scheduler.pool.size: 5</code> in <code>application.yml</code>, restart, compare <code>activeThreads</code> and bar chart heights before/after.</p></li><li><p>Query <code>GET /api/cluster/status</code> on either port; <code>duplicateCounts.BILLING_CYCLE</code> divided by expected single-instance count (&#8776;2 in 3 min at 90s rate) gives your factor &#8212; expect ~2&#215; with two nodes.</p></li><li><p>Lock Service sits between Scheduler Core and execution dispatch &#8212; it gates which instance may enter RUNNING state for a given task tick. On Diagram 1, draw an arrow from Lock Service to both Instance A and Instance B, with only one path open per tick.</p><p></p></li></ol>]]></content:encoded></item><item><title><![CDATA[Day 56: Global Rate Limiting — Distributed Rate Limiter for Gateway Logins]]></title><description><![CDATA[The Spring Boot Trap]]></description><link>https://javatsc.substack.com/p/day-56-global-rate-limiting-distributed</link><guid isPermaLink="false">https://javatsc.substack.com/p/day-56-global-rate-limiting-distributed</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Sat, 25 Jul 2026 01:45:44 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!tHqy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24c5c318-e010-45e0-8a5a-d6b445e0419f_1075x612.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>The Spring Boot Trap</h2><blockquote><p>A junior engineer reaches for Spring&#8217;s <code>@RateLimiter</code> annotation from Resilience4j, or wires up Bucket4j with an in-memory <code>ConcurrentHashMap</code>. The code is clean. Tests pass. In staging, with a single node and synthetic load, it holds.</p><p>Then production happens.</p><p>Your Gateway cluster has twelve nodes behind an L4 load balancer. A credential-stuffing bot opens 120 connections &#8212; ten per node. Each node&#8217;s local <code>AtomicInteger</code> sees ten IDENTIFY packets. Your limit is 50 per minute. Every node reports: <em>&#8220;Under limit.&#8221;</em> The bot authenticates 120 sessions in thirty seconds. Your in-memory rate limiter protected nothing.</p><p>That is the locality problem. Any rate limiter that does not share state across nodes is theatre.</p></blockquote><div><hr></div><h2>The Failure Mode</h2><blockquote><p><strong>Why the naive fix also fails:</strong> The obvious next step is a shared Redis key with <code>INCR</code> + <code>EXPIRE</code>. Junior engineers write this as two round-trips:</p></blockquote><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;7abd4e86-926e-4f87-932e-11aae6ad5561&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">long count = redis.incr(key);           // round-trip 1
if (count == 1) redis.expire(key, 60);  // round-trip 2</code></pre></div><blockquote><p>Under concurrent load, two nodes hit <code>INCR</code> simultaneously before either fires <code>EXPIRE</code>. The key never expires. You&#8217;ve built a permanent ban instead of a sliding window. This is a classic TOCTOU race on a distributed counter.</p><p><strong>The thread cost:</strong> If each IDENTIFY triggers a synchronous Redis call on a platform thread, at 50,000 logins/second across the cluster you need 50,000 threads blocked on network I/O. At 1 MB stack each, that is 50 GB of thread stack memory &#8212; before your application does a single unit of work.</p><p><strong>GC pressure from key strings:</strong> A naive <code>Map&lt;String, RateLimitBucket&gt;</code> where the key is <code>"ratelimit:identify:" + ip</code> allocates a new <code>String</code> object per request. At scale the Eden space saturates in milliseconds. Stop-the-world minor GC pauses hit every 200&#8211;400 ms, causing cascading IDENTIFY timeouts on legitimate clients.</p></blockquote><div><hr></div><h2>The Flux Architecture</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!tHqy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24c5c318-e010-45e0-8a5a-d6b445e0419f_1075x612.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!tHqy!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24c5c318-e010-45e0-8a5a-d6b445e0419f_1075x612.png 424w, /__u/substackcdn.com/image/fetch/$s_!tHqy!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24c5c318-e010-45e0-8a5a-d6b445e0419f_1075x612.png 848w, /__u/substackcdn.com/image/fetch/$s_!tHqy!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24c5c318-e010-45e0-8a5a-d6b445e0419f_1075x612.png 1272w, /__u/substackcdn.com/image/fetch/$s_!tHqy!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24c5c318-e010-45e0-8a5a-d6b445e0419f_1075x612.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!tHqy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24c5c318-e010-45e0-8a5a-d6b445e0419f_1075x612.png" width="526" height="299.45302325581395" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/24c5c318-e010-45e0-8a5a-d6b445e0419f_1075x612.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:612,&quot;width&quot;:1075,&quot;resizeWidth&quot;:526,&quot;bytes&quot;:110357,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://javatsc.substack.com/i/203062026?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24c5c318-e010-45e0-8a5a-d6b445e0419f_1075x612.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!tHqy!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24c5c318-e010-45e0-8a5a-d6b445e0419f_1075x612.png 424w, /__u/substackcdn.com/image/fetch/$s_!tHqy!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24c5c318-e010-45e0-8a5a-d6b445e0419f_1075x612.png 848w, /__u/substackcdn.com/image/fetch/$s_!tHqy!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24c5c318-e010-45e0-8a5a-d6b445e0419f_1075x612.png 1272w, /__u/substackcdn.com/image/fetch/$s_!tHqy!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24c5c318-e010-45e0-8a5a-d6b445e0419f_1075x612.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/javatsc.substack.com/p/day-56-global-rate-limiting-distributed">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 55 — The Edge Proxy: Routing WebSocket Upgrades at the Boundary]]></title><description><![CDATA[Phase 4: The Gateway | Building Discord: From Socket to Scale]]></description><link>https://javatsc.substack.com/p/day-55-the-edge-proxy-routing-websocket</link><guid isPermaLink="false">https://javatsc.substack.com/p/day-55-the-edge-proxy-routing-websocket</guid><dc:creator><![CDATA[System Design With Java]]></dc:creator><pubDate>Wed, 22 Jul 2026 01:45:04 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!f7j2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda74c097-1aca-44e4-aadb-e2d713682d92_1125x625.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>The Spring Boot Trap</h2><blockquote><p>A junior engineer inherits a WebSocket service running fine on a single node. Traffic grows. The obvious fix: throw Nginx in front, configure <code>upstream</code> with three backend servers, call it done.</p></blockquote><pre><code><code>upstream gateway_cluster {
    server node1:9001;
    server node2:9002;
    server node3:9003;
}</code></code></pre><blockquote><p>This works for HTTP. It silently destroys WebSocket.</p><p>The problem is not Nginx&#8217;s configuration. It is the engineer&#8217;s mental model. HTTP is stateless &#8212; every request is self-contained, and round-robin distribution is correct. WebSocket is stateful. The moment a client completes the HTTP Upgrade handshake, it establishes a persistent TCP connection to a <em>specific backend process</em>. All future frames traverse that exact socket. Routing the upgrade request to node1 and the next frame to node2 is not load balancing &#8212; it is data corruption.</p><p>Spring Boot&#8217;s <code>@EnableWebSocketMessageBroker</code> hides this entirely. The abstraction manages sessions internally, and the developer never sees the connection identity. At 10,000 users this breaks: STOMP session IDs are stored in memory on one node. Any reconnection that lands on a different node starts a cold session. Authentication, subscriptions, and presence state are all gone.</p></blockquote><h2>The Failure Mode</h2><blockquote><p>Nginx with default configuration silently kills WebSocket connections in three ways.</p><p><strong>Timeout eviction.</strong> <code>proxy_read_timeout</code> defaults to 60 seconds. A WebSocket connection with no traffic &#8212; a user reading, not typing &#8212; looks idle to Nginx and gets dropped. The client reconnects. The reconnect hits a different node. Session is lost.</p><p><strong>Missing upgrade headers.</strong> The HTTP Upgrade handshake requires <code>Connection: Upgrade</code> and <code>Upgrade: websocket</code> headers to be forwarded verbatim to the backend. Nginx strips hop-by-hop headers by default. Without explicit <code>proxy_set_header</code> directives, the backend never sees the Upgrade request and returns a 200 with an HTTP body. The client&#8217;s WebSocket library closes immediately.</p><p><strong>Source IP erasure.</strong> After SSL termination, every connection appears to originate from <code>127.0.0.1</code>. Rate limiting by IP becomes useless. Per-user throttling breaks. Audit logs show the proxy address, not the real client. You need <code>proxy_set_header X-Forwarded-For $remote_addr</code> &#8212; and the backend must trust and parse it, not ignore it.</p><p>The deeper failure is architectural. A load balancer that does not understand session locality is not a load balancer for stateful services. It is a random connection redirector.</p></blockquote><h2>The Flux Architecture</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!f7j2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda74c097-1aca-44e4-aadb-e2d713682d92_1125x625.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!f7j2!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda74c097-1aca-44e4-aadb-e2d713682d92_1125x625.png 424w, /__u/substackcdn.com/image/fetch/$s_!f7j2!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda74c097-1aca-44e4-aadb-e2d713682d92_1125x625.png 848w, /__u/substackcdn.com/image/fetch/$s_!f7j2!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda74c097-1aca-44e4-aadb-e2d713682d92_1125x625.png 1272w, /__u/substackcdn.com/image/fetch/$s_!f7j2!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda74c097-1aca-44e4-aadb-e2d713682d92_1125x625.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!f7j2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda74c097-1aca-44e4-aadb-e2d713682d92_1125x625.png" width="534" height="296.6666666666667" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/da74c097-1aca-44e4-aadb-e2d713682d92_1125x625.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:625,&quot;width&quot;:1125,&quot;resizeWidth&quot;:534,&quot;bytes&quot;:121529,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://javatsc.substack.com/i/203046080?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda74c097-1aca-44e4-aadb-e2d713682d92_1125x625.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!f7j2!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda74c097-1aca-44e4-aadb-e2d713682d92_1125x625.png 424w, /__u/substackcdn.com/image/fetch/$s_!f7j2!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda74c097-1aca-44e4-aadb-e2d713682d92_1125x625.png 848w, /__u/substackcdn.com/image/fetch/$s_!f7j2!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda74c097-1aca-44e4-aadb-e2d713682d92_1125x625.png 1272w, /__u/substackcdn.com/image/fetch/$s_!f7j2!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda74c097-1aca-44e4-aadb-e2d713682d92_1125x625.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The Edge Proxy layer in Flux is built on three principles.</p><p><strong>Consistent Hashing for Session Locality.</strong> Every connection carries a user identity &#8212; either in the URL path (<code>/gateway?user_id=42</code>), a cookie, or an <code>X-User-Id</code> header. The proxy hashes this identity against a ring of backend nodes. For any given user, <code>hash(userId) mod ringSize</code> always resolves to the same node, regardless of which proxy instance handles the request. This means reconnections land on the same backend. Session state survives transient network interruptions.</p><p><strong>Transparent TCP Tunneling.</strong> Once the proxy selects a backend, it opens a raw TCP socket to that node and splices the two streams: client-to-backend and backend-to-client. No WebSocket frame parsing happens at the proxy layer. The proxy is deliberately dumb about application protocol &#8212; it moves bytes, not messages. This keeps the hot path allocation-free.</p><p><strong>Virtual Thread Bidirectional Pumps.</strong> Each tunnel requires two blocking I/O loops: one reading from the client socket and writing to the backend, one reading from the backend and writing to the client. With platform threads, this costs two OS threads per connection &#8212; catastrophic at 100K users. With Virtual Threads, both loops are lightweight continuations scheduled on the carrier thread pool. Memory cost drops from ~1MB per thread to ~2KB per virtual thread stack.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!KiVp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a7bf47-22a7-45b6-af4b-899fd8542ef5_1075x750.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!KiVp!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a7bf47-22a7-45b6-af4b-899fd8542ef5_1075x750.png 424w, /__u/substackcdn.com/image/fetch/$s_!KiVp!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a7bf47-22a7-45b6-af4b-899fd8542ef5_1075x750.png 848w, /__u/substackcdn.com/image/fetch/$s_!KiVp!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a7bf47-22a7-45b6-af4b-899fd8542ef5_1075x750.png 1272w, /__u/substackcdn.com/image/fetch/$s_!KiVp!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a7bf47-22a7-45b6-af4b-899fd8542ef5_1075x750.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!KiVp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a7bf47-22a7-45b6-af4b-899fd8542ef5_1075x750.png" width="564" height="393.48837209302326" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/02a7bf47-22a7-45b6-af4b-899fd8542ef5_1075x750.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:750,&quot;width&quot;:1075,&quot;resizeWidth&quot;:564,&quot;bytes&quot;:105713,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://javatsc.substack.com/i/203046080?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a7bf47-22a7-45b6-af4b-899fd8542ef5_1075x750.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!KiVp!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a7bf47-22a7-45b6-af4b-899fd8542ef5_1075x750.png 424w, /__u/substackcdn.com/image/fetch/$s_!KiVp!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a7bf47-22a7-45b6-af4b-899fd8542ef5_1075x750.png 848w, /__u/substackcdn.com/image/fetch/$s_!KiVp!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a7bf47-22a7-45b6-af4b-899fd8542ef5_1075x750.png 1272w, /__u/substackcdn.com/image/fetch/$s_!KiVp!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a7bf47-22a7-45b6-af4b-899fd8542ef5_1075x750.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Implementation Deep Dive</h2><h3>GitHub Link :</h3><p><a href="https://github.com/sysdr/discord-flux-p/tree/main/day55/flux-edge-proxy">https://github.com/sysdr/discord-flux-p/tree/main/day55/flux-edge-proxy</a></p><h3>Consistent Hash Ring</h3><p>The hash ring stores <code>virtualNodes</code> copies of each backend node to ensure even distribution. Each virtual node maps a hash value to a physical backend address. When routing a connection:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;03b2fd16-b2d1-4b5f-ab33-b0f6cc093b91&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">long hash = murmur3(userId);
NavigableMap&lt;Long, InetSocketAddress&gt; tailMap = ring.tailMap(hash);
InetSocketAddress backend = tailMap.isEmpty()
    ? ring.firstEntry().getValue()   // wrap around
    : tailMap.firstEntry().getValue();</code></pre></div><p><code>TreeMap.tailMap()</code> gives O(log n) lookup. No lock is needed on read paths if the ring is rebuilt via <code>Collections.unmodifiableNavigableMap()</code> on update.</p><h3>HTTP Upgrade Forwarding</h3><p>The proxy must forward the client&#8217;s original Upgrade request byte-for-byte to the backend, then splice the streams. Critical headers:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;c9665751-c6e2-43a9-aecf-7eb576383c6b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: &lt;client key&gt;
X-Forwarded-For: &lt;real client IP&gt;
X-User-Id: &lt;extracted user identity&gt;</code></pre></div><p>The backend responds with <code>101 Switching Protocols</code>. After the proxy forwards the 101 back to the client, both sockets enter tunnel mode &#8212; raw byte copying with no further HTTP parsing.</p><h3>Zero-Allocation Tunnel Loop</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;java&quot;,&quot;nodeId&quot;:&quot;a9059b05-3f34-4bd8-889a-795427289ff3&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-java">void pump(InputStream src, OutputStream dst, byte[] buffer) {
    try {
        int n;
        while ((n = src.read(buffer)) != -1) {
            dst.write(buffer, 0, n);
            dst.flush();
        }
    } catch (IOException ignored) {
        // Either side closed &#8212; tunnel is done
    }
}</code></pre></div><p>The <code>buffer</code> is allocated once per tunnel (8KB). No object creation in the loop. No WebSocket frame decoding. The proxy is a pipe, not a parser.</p><h3>Backend Health Tracking</h3><p>A <code>HealthMonitor</code> pings each backend over a lightweight HTTP <code>/health</code> endpoint every 5 seconds using Virtual Threads. If three consecutive pings fail, the node is marked <code>UNHEALTHY</code> and removed from the hash ring. Connections in flight are not terminated &#8212; the proxy drains them. New connections bypass the failed node until it recovers.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!Dx3C!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f762710-8aba-4487-974e-1045acebe748_1025x675.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!Dx3C!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f762710-8aba-4487-974e-1045acebe748_1025x675.png 424w, /__u/substackcdn.com/image/fetch/$s_!Dx3C!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f762710-8aba-4487-974e-1045acebe748_1025x675.png 848w, /__u/substackcdn.com/image/fetch/$s_!Dx3C!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f762710-8aba-4487-974e-1045acebe748_1025x675.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Dx3C!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f762710-8aba-4487-974e-1045acebe748_1025x675.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!Dx3C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f762710-8aba-4487-974e-1045acebe748_1025x675.png" width="512" height="337.1707317073171" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7f762710-8aba-4487-974e-1045acebe748_1025x675.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:675,&quot;width&quot;:1025,&quot;resizeWidth&quot;:512,&quot;bytes&quot;:129457,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://javatsc.substack.com/i/203046080?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f762710-8aba-4487-974e-1045acebe748_1025x675.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!Dx3C!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f762710-8aba-4487-974e-1045acebe748_1025x675.png 424w, /__u/substackcdn.com/image/fetch/$s_!Dx3C!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f762710-8aba-4487-974e-1045acebe748_1025x675.png 848w, /__u/substackcdn.com/image/fetch/$s_!Dx3C!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f762710-8aba-4487-974e-1045acebe748_1025x675.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Dx3C!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f762710-8aba-4487-974e-1045acebe748_1025x675.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Working Demo Link :</h3><div id="youtube2-yAKfgHkMji8" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;yAKfgHkMji8&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/yAKfgHkMji8?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h2>Production Readiness</h2><p><strong>Metrics to instrument:</strong></p><p><strong>MetricAlert Threshold</strong>Active tunnels per node&gt;80% of node capacityUpgrade failure rate&gt;0.1% over 1-minute windowBackend health check latency&gt;200msProxy buffer queue depth&gt;10K pending bytesVirtual thread countMonitor via <code>jcmd &lt;pid&gt; Thread.print</code></p><p><strong>What VisualVM shows:</strong> Under load, carrier thread count stays fixed (typically <code>Runtime.getRuntime().availableProcessors() * 2</code>). Virtual thread count grows proportionally to active tunnels. Heap allocation is flat &#8212; the reused byte arrays never escape to the old generation.</p><p><strong>The reconnection storm problem.</strong> When a backend node fails, all its clients reconnect simultaneously. A naive implementation re-hashes all of them to two remaining nodes, doubling load. Consistent hashing minimizes this: only the users whose hash range covered the failed node migrate. Everyone else stays put.</p><h2>Step-by-Step Guide</h2><h3>Prerequisites</h3><ul><li><p>Java 21+ (<code>java -version</code> should show <code>21.x</code> or higher)</p></li><li><p>Maven 3.9+</p></li><li><p>VisualVM (bundled with JDK or download separately)</p></li><li><p>Terminal with at least 3 panes (tmux or split terminal)</p></li></ul><h3>Execution</h3><pre><code><code>cd flux-edge-proxy
./start.sh</code></code></pre><p><code>start.sh</code> launches three <code>GatewayNode</code> instances on ports 9001&#8211;9003, then starts the <code>EdgeProxy</code> on port 8080 with the dashboard on port 8090.</p><h3>Verification</h3><pre><code><code>./demo.sh</code></code></pre><p>The demo script connects 50 WebSocket clients with random user IDs and prints which backend each was routed to. Open <code>http://localhost:8090/dashboard</code> to see the live routing table, per-node connection counts, and hash ring visualization.</p><p>Run <code>./verify.sh</code> to confirm consistent routing: the same user ID always lands on the same node.</p><p>In VisualVM, attach to the <code>EdgeProxy</code> process. Observe:</p><ul><li><p>Carrier thread count: stable at <code>~16</code> (matches CPU core count)</p></li><li><p>Virtual thread count: grows with active connections, ~1 per active tunnel pair</p></li><li><p>Heap allocation rate: near-zero in steady state</p></li></ul><h3>Homework</h3><p><strong>Beginner:</strong> Add <code>X-Gateway-Node</code> response header so clients can log which backend they connected to.</p><p><strong>Intermediate:</strong> Implement weighted consistent hashing. Node3 has 2x capacity &#8212; give it 2x virtual nodes on the ring. Verify with <code>verify.sh</code> that approximately 50% of connections land on node3.</p><p><strong>Expert:</strong> Implement connection draining. When a node is removed from the ring, existing tunnels continue until the client disconnects. New connections never route to that node. Add a <code>/admin/drain?node=9002</code> endpoint to the dashboard and measure how long the drain takes under the demo load.</p>]]></content:encoded></item><item><title><![CDATA[Day 54 : Inter-Node Communication: The Gateway Message Bus]]></title><description><![CDATA[What you will build today: A 3-node Gateway cluster where each node maintains persistent TCP connections to every other node, routes events through a binary wire protocol with zero String allocations in the hot path, and enforces explicit backpressure using bounded queues &#8212; the same architectural pattern Discord uses to prevent a single slow node from taking down the entire cluster.]]></description><link>https://javatsc.substack.com/p/day-54-inter-node-communication-the</link><guid isPermaLink="false">https://javatsc.substack.com/p/day-54-inter-node-communication-the</guid><dc:creator><![CDATA[sysdai]]></dc:creator><pubDate>Sun, 19 Jul 2026 01:45:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!aaZP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc386f86-a8b5-4645-84e3-484e33ad03fc_4500x3100.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p><strong>What you will build today:</strong> A 3-node Gateway cluster where each node maintains persistent TCP connections to every other node, routes events through a binary wire protocol with zero String allocations in the hot path, and enforces explicit backpressure using bounded queues &#8212; the same architectural pattern Discord uses to prevent a single slow node from taking down the entire cluster.</p></blockquote><p><strong>What you will understand after today:</strong></p><ul><li><p>Why frameworks hide the slow consumer problem and how it kills production systems</p></li><li><p>How binary framing eliminates garbage pressure in the inter-node hot path</p></li><li><p>Why Virtual Threads are the exact right tool for persistent peer connections</p></li><li><p>How a <code>SubscriptionTable</code> turns an O(N&#178;) broadcast into a targeted forward</p></li></ul><div><hr></div><h2>Part 1 &#8212; The Theory</h2><h3>The &#8220;Spring Boot&#8221; Trap</h3><blockquote><p>A junior engineer hits the requirement: <em>&#8220;When User A on Gateway-1 sends a message to a channel where User B is on Gateway-2, Gateway-1 needs to forward that event.&#8221;</em> Their instinct: pull in Spring Cloud Bus, drop a RabbitMQ dependency, annotate with <code>@StreamListener</code>, and call it solved.</p></blockquote><p>Here&#8217;s what they just hid from themselves:</p><pre><code><code>// What Spring Cloud Bus does under the hood &#8212; every forwarded event
String json = objectMapper.writeValueAsString(event);  // Allocates String + char[] + byte[]
rabbitTemplate.convertAndSend("gateway.events", json); // Copies those bytes again</code></code></pre><p>At 50,000 events/second across a 20-node cluster, that&#8217;s 50,000 <code>ObjectMapper.writeValueAsString()</code> invocations per second. Each creates: a <code>String</code>, a backing <code>char[]</code>, and a <code>byte[]</code> for the UTF-8 encoding. Three heap allocations per event in the hot path. Your Eden space fills in milliseconds. Minor GC fires every 40&#8211;80ms. Users see it as jitter: a 2ms message delivery that occasionally spikes to 60ms. At Discord scale, that 60ms spike is a visible stutter in 100 million chat windows.</p><p>The deeper failure: Spring Cloud Bus gives you <strong>zero visibility</strong> into back-pressure. When RabbitMQ falls behind, your producers block silently on a <code>Channel.basicPublish()</code> inside a framework-managed thread pool. By the time you notice, your Gateway threads are exhausted and new WebSocket connections are being rejected.</p><div><hr></div><h3>The Failure Mode: The Slow Consumer Death Spiral</h3><p>The architectural failure is the <strong>slow consumer problem</strong>. Consider a 3-node Gateway cluster:</p><pre><code><code>Gateway-1 &#8594; [outbound queue] &#8594; TCP &#8594; Gateway-2 (overloaded, processing slowly)
                                   &#8594; TCP &#8594; Gateway-3 (healthy)</code></code></pre><p>If the queue feeding Gateway-2 is unbounded &#8212; the classic <code>LinkedList</code> or <code>LinkedBlockingQueue(Integer.MAX_VALUE)</code> &#8212; a traffic spike causes queue depth to grow at the rate of (production rate &#8722; consumption rate). At 10,000 events/second with Gateway-2 processing at 8,000 events/second, the queue grows by 2,000 entries/second. After 90 seconds: 180,000 event objects on heap. Each holding a <code>byte[]</code> payload. OOM in 10 minutes.</p><p>The JVM makes this worse. Those queued events are <em>tenured</em> &#8212; they survive enough minor GCs to be promoted to Old Gen. When Old Gen fills, you get a Stop-The-World Full GC. For 30 seconds, every Gateway-1 thread is frozen. Every client connected to Gateway-1 sees a 30-second message gap.</p><p><strong>Discord&#8217;s real lesson here</strong>: their initial presence broadcast was O(N&#178;). Every user status change went to every gateway node. The fix was <em>lazy subscription</em> &#8212; a <code>SubscriptionTable</code> mapping <code>channelId &#8594; Set&lt;nodeId&gt;</code>. You only forward to nodes that have actual subscribers. Presence updates for a channel with 3,000 members on 2 gateway nodes forward to exactly 2 nodes, not 50.</p><div><hr></div><h3>The Flux Architecture</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!aaZP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc386f86-a8b5-4645-84e3-484e33ad03fc_4500x3100.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!aaZP!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc386f86-a8b5-4645-84e3-484e33ad03fc_4500x3100.png 424w, /__u/substackcdn.com/image/fetch/$s_!aaZP!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc386f86-a8b5-4645-84e3-484e33ad03fc_4500x3100.png 848w, /__u/substackcdn.com/image/fetch/$s_!aaZP!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc386f86-a8b5-4645-84e3-484e33ad03fc_4500x3100.png 1272w, /__u/substackcdn.com/image/fetch/$s_!aaZP!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_webp, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc386f86-a8b5-4645-84e3-484e33ad03fc_4500x3100.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!aaZP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc386f86-a8b5-4645-84e3-484e33ad03fc_4500x3100.png" width="466" height="321.0151098901099" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fc386f86-a8b5-4645-84e3-484e33ad03fc_4500x3100.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1003,&quot;width&quot;:1456,&quot;resizeWidth&quot;:466,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!aaZP!, /__u/javatsc.substack.com/w_424, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc386f86-a8b5-4645-84e3-484e33ad03fc_4500x3100.png 424w, /__u/substackcdn.com/image/fetch/$s_!aaZP!, /__u/javatsc.substack.com/w_848, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc386f86-a8b5-4645-84e3-484e33ad03fc_4500x3100.png 848w, /__u/substackcdn.com/image/fetch/$s_!aaZP!, /__u/javatsc.substack.com/w_1272, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc386f86-a8b5-4645-84e3-484e33ad03fc_4500x3100.png 1272w, /__u/substackcdn.com/image/fetch/$s_!aaZP!, /__u/javatsc.substack.com/w_1456, /__u/javatsc.substack.com/c_limit, /__u/javatsc.substack.com/f_auto, /__u/javatsc.substack.com/q_auto:good, /__u/javatsc.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc386f86-a8b5-4645-84e3-484e33ad03fc_4500x3100.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/javatsc.substack.com/p/day-54-inter-node-communication-the">
              Read more
          </a>
      </p>
   ]]></content:encoded></item></channel></rss>