<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>juno - Delasport</title>
	<atom:link href="https://www.delasport.com/tag/juno/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.delasport.com</link>
	<description>We Deliver Sports</description>
	<lastBuildDate>Tue, 30 Sep 2025 14:58:07 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://www.delasport.com/wp-content/uploads/2025/09/cropped-favicon-150x150.png</url>
	<title>juno - Delasport</title>
	<link>https://www.delasport.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>How We Handle Thousands of Real-Time Events in Our Sportsbook</title>
		<link>https://www.delasport.com/how-we-handle-thousands-of-real-time-events-in-our-sportsbook/</link>
		
		<dc:creator><![CDATA[dash]]></dc:creator>
		<pubDate>Fri, 09 May 2025 11:07:36 +0000</pubDate>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[juno]]></category>
		<category><![CDATA[kafka]]></category>
		<category><![CDATA[pipeline]]></category>
		<category><![CDATA[real-time]]></category>
		<category><![CDATA[sports]]></category>
		<category><![CDATA[Sportsbook]]></category>
		<guid isPermaLink="false">https://www.delasport.com/?p=14206</guid>

					<description><![CDATA[<p>Picture this: You’re watching a high-stakes football match. A goal is scored in the 89th minute. Within a split second, your sportsbook app updates - odds shift, markets lock or open, and everything feels seamless. But behind that smooth front-end experience - pure complexity. Delasport's system has to handle thousands of these updates at once [&#8230;]</p>
<p>The post <a href="https://www.delasport.com/how-we-handle-thousands-of-real-time-events-in-our-sportsbook/">How We Handle Thousands of Real-Time Events in Our Sportsbook</a> first appeared on <a href="https://www.delasport.com">Delasport</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><strong>Picture this: You’re watching a high-stakes football match. A goal is scored in the 89th minute. Within a split second, your <a href="https://www.delasport.com/sportsbook-solution/" target="_blank" rel="noopener">sportsbook</a> app updates - odds shift, markets lock or open, and everything feels seamless.</strong></p>
<p><strong>But behind that smooth front-end experience - pure complexity.</strong></p>
<p><span data-contrast="auto">Delasport's system has to handle </span>thousands of these updates at once - goals, fouls, injuries, substitutions, overtime - all in real time, across hundreds of matches. The scale is staggering, but it’s also where the fun begins (at least for those of us who enjoy a good concurrency challenge).</p>
<p>Here’s how we make it work using Java, multithreading, Kafka<span data-contrast="auto">, and a healthy respect for immutability, as told by Delasport's Java Team Lead, Georgi Stoyanov.</span></p>
<h3><b><span data-contrast="auto">The Challenge: Real-Time, High-Volume Event Processing</span></b></h3>
<p><span data-contrast="auto">In a live betting environment, speed isn’t just important - it’s non-negotiable.</span></p>
<p><span data-contrast="auto">Every single change in the game can affect:</span></p>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="1" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="1" data-aria-level="1"><span data-contrast="auto">Which markets are open or suspended</span></li>
</ul>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="1" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="2" data-aria-level="1"><span data-contrast="auto">Live odds</span></li>
</ul>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="1" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="3" data-aria-level="1"><span data-contrast="auto">Cash-out availability</span></li>
</ul>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="1" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="4" data-aria-level="1"><span data-contrast="auto">What the front-end needs to show, immediately</span></li>
</ul>
<p><span data-contrast="auto">Multiply that across hundreds or even thousands of simultaneous matches. This isn’t just a stream of updates - it’s a flood. And the system must react in near real time, without dropping a beat.</span></p>
<h3><b><span data-contrast="auto">Our Approach: Java Multithreading + Kafka Partitioning</span></b><span data-ccp-props="{}"> </span></h3>
<p><span data-contrast="auto">We’ve built our system around a simple principle: </span>divide and conquer.</p>
<p><b><span data-contrast="auto">Kafka: The Event Traffic Controller</span></b><span data-ccp-props="{}"> </span></p>
<p><span data-contrast="auto">Kafka acts as our real-time data backbone. Each match has its own stream of updates, funneled into a Kafka topic and partitioned - often by match ID.</span><span data-ccp-props="{}"> </span></p>
<p><span data-contrast="auto">Why partitions? Because they allow us to </span>scale horizontally and process data in parallel<span data-contrast="auto">. Kafka also guarantees message order within a partition, which is critical when timing matters - like determining whether a goal came before a red card.</span><span data-ccp-props="{}"> </span></p>
<p><b><span data-contrast="auto">Java Threads: The Processing Engine</span></b><span data-ccp-props="{}"> </span></p>
<p><span data-contrast="auto">Each Kafka partition is handled by a dedicated Java thread (or thread pool, when necessary). That thread is responsible for:</span><span data-ccp-props="{}"> </span></p>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="2" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="1" data-aria-level="1"><span data-contrast="auto">Consuming and deserializing the event</span><span data-ccp-props="{}"> </span></li>
</ul>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="2" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="2" data-aria-level="1"><span data-contrast="auto">Recalculating odds based on the new state</span><span data-ccp-props="{}"> </span></li>
</ul>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="2" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="3" data-aria-level="1"><span data-contrast="auto">Updating the state of relevant markets</span><span data-ccp-props="{}"> </span></li>
</ul>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="2" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="4" data-aria-level="1"><span data-contrast="auto">Generating fresh data for the front end</span><span data-ccp-props="{}"> </span></li>
</ul>
<p><span data-contrast="auto">The outcome is massively parallel processing - ordered, efficient, and fast. Each match is handled independently, which allows us to scale our processing across CPU cores and servers with minimal contention.</span><span data-ccp-props="{}"> </span></p>
<p><b><span data-contrast="auto">Immutability: Our Best Friend in a Concurrent World</span></b><span data-ccp-props="{}"> </span></p>
<p><span data-contrast="auto">Concurrency is tricky. Bugs caused by shared mutable state are some of the most subtle and frustrating in software engineering.</span><span data-ccp-props="{}"> </span></p>
<p><span data-contrast="auto">That’s why we’ve built our system around </span>immutable data structures<span data-contrast="auto">. Each event message, once deserialized, is wrapped into an immutable object. Any transformation or update creates a new object.</span><span data-ccp-props="{}"> </span></p>
<p><span data-contrast="auto">The benefits:</span><span data-ccp-props="{}"> </span></p>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="3" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="1" data-aria-level="1"><span data-contrast="auto">Thread safety without locks</span><span data-ccp-props="{}"> </span></li>
</ul>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="3" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="2" data-aria-level="1"><span data-contrast="auto">No risk of race conditions</span><span data-ccp-props="{}"> </span></li>
</ul>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="3" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="3" data-aria-level="1"><span data-contrast="auto">Easier debugging and reasoning about system behavior</span><span data-ccp-props="{}"> </span></li>
</ul>
<p><span data-contrast="auto">This design choice has dramatically improved the reliability of our processing pipeline - and simplified how our developers work with data.</span><span data-ccp-props="{}"> </span></p>
<h3><b><span data-contrast="auto">A Real-World Example</span></b><span data-ccp-props="{}"> </span></h3>
<p><span data-contrast="auto">Let’s walk through what happens when a goal is scored in Match 5678:</span><span data-ccp-props="{}"> </span></p>
<p>1. Kafka ingests the event into the topic match-5678-events.</p>
<p>2. The message is routed to the appropriate partition.</p>
<p>3. A Java thread assigned to that partition picks up the message.</p>
<p>4. It processes the event: updates internal state, recalculates odds, and generates a new view of the market.</p>
<p>5. The updated data is pushed to the front end, usually within milliseconds.</p>
<p><span data-contrast="auto">All of this happens with minimal locking, no shared mutable state, and no interference from events in other matches.</span><span data-ccp-props="{}"> </span></p>
<h3><b><span data-contrast="auto">Lessons Learned</span></b><span data-ccp-props="{&quot;335559685&quot;:0}"> </span></h3>
<p><span data-contrast="auto">After building and refining this system in production, a few lessons stand out:</span><span data-ccp-props="{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;335551550&quot;:0,&quot;335551620&quot;:0,&quot;335559738&quot;:300,&quot;335559739&quot;:300}"> </span></p>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="5" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="2" data-aria-level="1"><b><span data-contrast="auto">Thread pools need tuning</span></b><span data-contrast="auto">. Too many threads introduce overhead and can lead to excessive context switching; too few, and you create bottlenecks under load.</span><span data-ccp-props="{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;335551550&quot;:0,&quot;335551620&quot;:0,&quot;335559738&quot;:300,&quot;335559739&quot;:300}"> </span></li>
</ul>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="5" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="3" data-aria-level="1"><b><span data-contrast="auto">Kafka’s partitioning model is a superpower</span></b><span data-contrast="auto">, especially when used to enforce logical boundaries like match or market IDs. It allows us to scale cleanly and ensures ordered, isolated processing.</span><span data-ccp-props="{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;335551550&quot;:0,&quot;335551620&quot;:0,&quot;335559738&quot;:300,&quot;335559739&quot;:300}"> </span></li>
</ul>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="5" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="4" data-aria-level="1"><b><span data-contrast="auto">Immutability pays off</span></b><span data-contrast="auto">. It removes an entire class of concurrency bugs, improves reliability, and simplifies the mental model for developers working in a multi-threaded environment.</span><span data-ccp-props="{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;335551550&quot;:0,&quot;335551620&quot;:0,&quot;335559738&quot;:300,&quot;335559739&quot;:300}"> </span></li>
</ul>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="5" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="5" data-aria-level="1"><b><span data-contrast="auto">Monitoring is critical</span></b><span data-contrast="auto">. With so many moving parts, we rely heavily on observability - metrics around latency, thread activity, queue depth, and partition lag help us maintain performance and spot issues before they escalate.</span><span data-ccp-props="{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;335551550&quot;:0,&quot;335551620&quot;:0,&quot;335559738&quot;:300,&quot;335559739&quot;:300}"> </span></li>
</ul>
<ul>
<li data-leveltext="" data-font="Symbol" data-listid="5" data-list-defn-props="{&quot;335552541&quot;:1,&quot;335559685&quot;:720,&quot;335559991&quot;:360,&quot;469769226&quot;:&quot;Symbol&quot;,&quot;469769242&quot;:[8226],&quot;469777803&quot;:&quot;left&quot;,&quot;469777804&quot;:&quot;&quot;,&quot;469777815&quot;:&quot;hybridMultilevel&quot;}" aria-setsize="-1" data-aria-posinset="6" data-aria-level="1"><b><span data-contrast="auto">We're exploring virtual threads</span></b><span data-contrast="auto">. With the introduction of Project Loom in modern Java, virtual threads offer a promising path to simplify concurrency even further - allowing us to handle many more lightweight tasks with less tuning and overhead. We’re currently evaluating how they might fit into our architecture, particularly in areas with high I/O wait times or blocking operations.</span><span data-ccp-props="{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;335551550&quot;:0,&quot;335551620&quot;:0,&quot;335559738&quot;:300,&quot;335559739&quot;:300}"> </span></li>
</ul>
<p><span data-contrast="auto">Building a scalable, real-time sportsbook engine in Java has been one of the most rewarding engineering challenges we've tackled. It forced us to think deeply about concurrency, architecture, and fault tolerance - while still delivering a seamless experience to users who expect everything to just work.</span><span data-ccp-props="{}"> </span></p>
<p><span data-contrast="auto">If you're working on anything in the real-time or high-throughput space - trading systems, analytics platforms, even multiplayer games - many of the same principles apply.</span><span data-ccp-props="{}"> </span></p>
<p><span data-contrast="auto">And if you're deep in the trenches of Java concurrency and event-driven architecture, I'd love to hear how you’re approaching it.</span></p>
<p>&nbsp;</p>
<p><strong><em>Sounds interesting? Delasport will be at the upcoming <a href="https://jprime.io/" target="_blank" rel="noopener">jPrime 2025</a> where you can learn more about how our Java teams operate and what the opportunities for you are!</em></strong></p><p>The post <a href="https://www.delasport.com/how-we-handle-thousands-of-real-time-events-in-our-sportsbook/">How We Handle Thousands of Real-Time Events in Our Sportsbook</a> first appeared on <a href="https://www.delasport.com">Delasport</a>.</p>]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
