<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jeremiah Deku</title>
    <description>The latest articles on DEV Community by Jeremiah Deku (@jeremiah_dek).</description>
    <link>https://dev.to/jeremiah_dek</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1716007%2Ff01aee24-9f43-4014-9c0f-3ffafdbaf7e9.png</url>
      <title>DEV Community: Jeremiah Deku</title>
      <link>https://dev.to/jeremiah_dek</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jeremiah_dek"/>
    <language>en</language>
    <item>
      <title>How I Fixed a Race Condition in a Live Seat Booking System (And Lost Sleep Over It)</title>
      <dc:creator>Jeremiah Deku</dc:creator>
      <pubDate>Sun, 29 Mar 2026 00:28:15 +0000</pubDate>
      <link>https://dev.to/jeremiah_dek/how-i-fixed-a-race-condition-in-a-live-seat-booking-system-and-lost-sleep-over-it-48ii</link>
      <guid>https://dev.to/jeremiah_dek/how-i-fixed-a-race-condition-in-a-live-seat-booking-system-and-lost-sleep-over-it-48ii</guid>
      <description>&lt;p&gt;𝗧𝘄𝗼 𝘂𝘀𝗲𝗿𝘀. 𝗢𝗻𝗲 𝘀𝗲𝗮𝘁. 𝗧𝗼𝘁𝗮𝗹 𝗰𝗵𝗮𝗼𝘀.&lt;br&gt;
It was a regular Tuesday on a client project — a bus ticket booking platform. Everything looked fine until a support ticket landed: two passengers had been assigned the same seat on the same trip.&lt;/p&gt;

&lt;p&gt;My first instinct? "That can't happen — I have a check before booking." Famous last words.&lt;/p&gt;

&lt;h2&gt;
  
  
  𝗪𝗵𝗮𝘁 𝘄𝗮𝘀 𝗮𝗰𝘁𝘂𝗮𝗹𝗹𝘆 𝗵𝗮𝗽𝗽𝗲𝗻𝗶𝗻𝗴:
&lt;/h2&gt;

&lt;p&gt;User A and User B both queried the seat at nearly the same millisecond. Both saw it as available. Both proceeded to book. The database updated twice — same seat, two owners.&lt;/p&gt;

&lt;h2&gt;
  
  
  𝗠𝘆 𝗳𝗶𝗿𝘀𝘁 (𝘄𝗿𝗼𝗻𝗴) 𝗮𝘁𝘁𝗲𝗺𝗽𝘁𝘀
&lt;/h2&gt;

&lt;p&gt;I tried a simple if check before updating — reading the seat status, then writing. Seemed logical. Broke immediately under any real concurrency. Read-then-write is not atomic. The window between those two operations is exactly where race conditions live.&lt;/p&gt;

&lt;p&gt;Then I tried a client-side flag. Also wrong. Socket.io events can arrive out of order, and the UI state is not a source of truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: atomic update + real-time lock broadcast
&lt;/h2&gt;

&lt;p&gt;The solution was to collapse the read and the write into a single atomic MongoDB operation — and pair it with a Socket.io broadcast so every connected client sees the lock instantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  // Atomic Updates + Socket.io Real-Time Lock
&lt;/h2&gt;

&lt;p&gt;async function reserveSeat(tripId, seatNo, userId) {&lt;/p&gt;

&lt;p&gt;// Prevents Race Conditions&lt;br&gt;
  const trip = await Trip.findOneAndUpdate(&lt;br&gt;
    { _id: tripId, "seats.no": seatNo, "seats.status": "available" },&lt;br&gt;
    { $set: { "seats.$.status": "locked", "seats.$.heldBy": userId } },&lt;br&gt;
    { new: true }&lt;br&gt;
  );&lt;/p&gt;

&lt;p&gt;if (!trip) throw new Error("Seat already taken!");&lt;/p&gt;

&lt;p&gt;// Broadcast the 'Lock' to all travelers&lt;br&gt;
  io.emit("seat_locked", { tripId, seatNo });&lt;br&gt;
  console.log(&lt;code&gt;Seat ${seatNo} secured for User ${userId}&lt;/code&gt;);&lt;br&gt;
}&lt;/p&gt;

&lt;h2&gt;
  
  
  𝗪𝗵𝘆 𝘁𝗵𝗶𝘀 𝘄𝗼𝗿𝗸𝘀 — 𝗹𝗶𝗻𝗲 𝗯𝘆 𝗹𝗶𝗻𝗲
&lt;/h2&gt;

&lt;p&gt;1️⃣ 𝙏𝙝𝙚 𝙦𝙪𝙚𝙧𝙮 𝙘𝙤𝙣𝙙𝙞𝙩𝙞𝙤𝙣 𝙞𝙨 𝙩𝙝𝙚 𝙜𝙪𝙖𝙧𝙙&lt;br&gt;
"seats.status": "available" means MongoDB only updates if the seat is still available at the exact moment of the write. If two requests arrive simultaneously, only one will match — the other gets null.&lt;/p&gt;

&lt;p&gt;2️⃣ 𝙛𝙞𝙣𝙙𝙊𝙣𝙚𝘼𝙣𝙙𝙐𝙥𝙙𝙖𝙩𝙚 𝙞𝙨 𝙖𝙩𝙤𝙢𝙞𝙘 𝙖𝙩 𝙩𝙝𝙚 𝙙𝙤𝙘𝙪𝙢𝙚𝙣𝙩 𝙡𝙚𝙫𝙚𝙡&lt;br&gt;
MongoDB guarantees that the find-and-update happens as a single operation. No other write can slip in between. This is the core of the fix.&lt;/p&gt;

&lt;p&gt;3️⃣ 𝙏𝙝𝙚 𝙣𝙪𝙡𝙡 𝙘𝙝𝙚𝙘𝙠 𝙞𝙨 𝙮𝙤𝙪𝙧 𝙚𝙧𝙧𝙤𝙧 𝙗𝙤𝙪𝙣𝙙𝙖𝙧𝙮&lt;br&gt;
If trip is null, the seat was already taken. Throw a clear error — don't silently fail. The client can catch this and show the user a friendly message.&lt;/p&gt;

&lt;p&gt;4️⃣ 𝙎𝙤𝙘𝙠𝙚𝙩.𝙞𝙤 𝙗𝙧𝙤𝙖𝙙𝙘𝙖𝙨𝙩𝙨 𝙩𝙝𝙚 𝙡𝙤𝙘𝙠 𝙞𝙢𝙢𝙚𝙙𝙞𝙖𝙩𝙚𝙡𝙮&lt;br&gt;
Once the DB confirms the lock, we emit seat_locked to all connected clients. Every user's seat map updates in real time — no polling, no stale UI.&lt;/p&gt;

&lt;p&gt;𝗧𝗵𝗲 𝗯𝗶𝗴𝗴𝗲𝘀𝘁 𝗹𝗲𝘀𝘀𝗼𝗻&lt;br&gt;
Race conditions don't announce themselves. They hide behind low traffic and happy paths. This bug only surfaced because two users happened to book at the same moment — something that's guaranteed to happen at scale.&lt;/p&gt;

&lt;p&gt;The fix isn't just about MongoDB. It's a mindset shift: never trust a read before a write in a concurrent system. Push your guard logic into the database operation itself, where it's atomic.&lt;/p&gt;

&lt;p&gt;𝐻𝑎𝑣𝑒 𝑦𝑜𝑢 𝑟𝑢𝑛 𝑖𝑛𝑡𝑜 𝑟𝑎𝑐𝑒 𝑐𝑜𝑛𝑑𝑖𝑡𝑖𝑜𝑛𝑠 𝑖𝑛 𝑦𝑜𝑢𝑟 𝑜𝑤𝑛 𝑝𝑟𝑜𝑗𝑒𝑐𝑡𝑠? 𝐼'𝑑 𝑙𝑜𝑣𝑒 𝑡𝑜 ℎ𝑒𝑎𝑟 ℎ𝑜𝑤 𝑦𝑜𝑢 ℎ𝑎𝑛𝑑𝑙𝑒𝑑 𝑖𝑡.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzm5u0irvpynerlxeqq2e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzm5u0irvpynerlxeqq2e.png" alt=" " width="800" height="947"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>notionchallenge</category>
      <category>ai</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
