<?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: David Mashiah</title>
    <description>The latest articles on DEV Community by David Mashiah (@mashiah).</description>
    <link>https://dev.to/mashiah</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4219114%2Fe189016f-f25e-496b-a31a-25ddbba52439.jpeg</url>
      <title>DEV Community: David Mashiah</title>
      <link>https://dev.to/mashiah</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mashiah"/>
    <language>en</language>
    <item>
      <title>My load test had 1,000 players. None of them were late.</title>
      <dc:creator>David Mashiah</dc:creator>
      <pubDate>Mon, 02 Nov 2026 06:42:58 +0000</pubDate>
      <link>https://dev.to/mashiah/my-load-test-had-1000-players-none-of-them-were-late-59cp</link>
      <guid>https://dev.to/mashiah/my-load-test-had-1000-players-none-of-them-were-late-59cp</guid>
      <description>&lt;p&gt;&lt;em&gt;Before the first event I ran 1 vs 100 against a thousand simulated players, and nothing broke. Then a lecture hall of real people broke it with a fraction of that. The test measured load correctly. It just never contained the one thing real people always do: arrive late.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I tested 1 vs 100 properly before anyone played it. A script opened a thousand simulated players over real WebSockets, started a question, and had all of them answer in the same instant: the thundering herd, the worst moment a live quiz has.&lt;/p&gt;

&lt;p&gt;It held. No dropped connections, the question reached every player in tens of milliseconds, and the reveal came back in under half a second.&lt;/p&gt;

&lt;p&gt;At the first real event, it broke anyway. Not under load. Under people.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the test could not contain
&lt;/h2&gt;

&lt;p&gt;Here is what the script did, in order: connect every player, wait until every one of them has joined, and only then press Start.&lt;/p&gt;

&lt;p&gt;That is the one order a real room never follows. In a lecture hall, people are still scanning the QR code when the host decides the room looks full. The game had a rule for anyone who joined after Start: watch, do not play. My thousand bots never triggered it, because not one of them was late. Everyone in the real room after the first 45 or so was, and their phones showed every question and never let them answer. &lt;a href="https://davidmashiah.com/notes/the-room-filled-after-i-pressed-start" rel="noopener noreferrer"&gt;The rule and the fix are their own note.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The test was faithful about load and wrong about time. It measured how many people the server could hold, and assumed they would all arrive at once, on cue, and stay on the page. Real people arrive late, switch tabs and reload. None of that is load, and all of it is what broke.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first ten minutes
&lt;/h2&gt;

&lt;p&gt;The first people with the problem came to me, and I did not know what it was. I went around to them, reassured them, and opened my laptop next to them to look. Technically, nothing was wrong anywhere I could see. The server was healthy and the game was running.&lt;/p&gt;

&lt;p&gt;I told them their answers were being counted. I believed it. They were not, and I did not know that yet.&lt;/p&gt;

&lt;p&gt;When more and more people had the same problem, I went outside to deal with it properly, making phone call after phone call to understand what was happening.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not starting again
&lt;/h2&gt;

&lt;p&gt;After about ten minutes the event coordinator came out to find me and asked what was going on. Her suggestion was to start the entire event again.&lt;/p&gt;

&lt;p&gt;I asked her not to. Restarting would have thrown away the game for everyone who was playing fine, to fix it for the people who were not. Instead I asked her to tell the crowd that anyone hit by the bug would go through to the next stage rather than be eliminated.&lt;/p&gt;

&lt;p&gt;That kept the event moving and kept the people who had been wronged in the game. Meanwhile I changed the rule and deployed the fix while the event was still running, and the stranded players came back in at the next question.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a load test is for
&lt;/h2&gt;

&lt;p&gt;A load test answers one question well: can the server take this many people at once. It is worth running, and mine was right.&lt;/p&gt;

&lt;p&gt;It cannot answer the question that decided the night: what happens when people do not behave like a script. That needs a different test, one that is written from watching a real room: people joining after the start, leaving the page, coming back. Measuring the wrong thing precisely felt like safety. It was only confidence.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;First published on &lt;a href="https://davidmashiah.com/notes/none-of-them-were-late" rel="noopener noreferrer"&gt;davidmashiah.com&lt;/a&gt;, with the rest of my notes on real-time systems, machine learning reliability and supply chains.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>performance</category>
      <category>scalability</category>
      <category>testing</category>
    </item>
    <item>
      <title>One Durable Object per room, and a rule that stranded a hall</title>
      <dc:creator>David Mashiah</dc:creator>
      <pubDate>Sat, 31 Oct 2026 21:09:37 +0000</pubDate>
      <link>https://dev.to/mashiah/one-durable-object-per-room-and-a-rule-that-stranded-a-hall-59dc</link>
      <guid>https://dev.to/mashiah/one-durable-object-per-room-and-a-rule-that-stranded-a-hall-59dc</guid>
      <description>&lt;p&gt;&lt;em&gt;At a faculty event the vice dean played 1 vs 100 against a room of students. About 45 of them got into the game. Everyone after that got a phone that showed the questions and never let them answer. Nothing had crashed. A rule that was correct on paper had met a real room.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;1 vs 100 is a live multiplayer quiz for a lecture hall: one person on stage against the crowd on their phones, everyone answering the same question against the same clock.&lt;/p&gt;

&lt;p&gt;The first time it ran at a real faculty event, the vice dean was The One. About 45 students got into the game. The rest of the room was holding phones that showed every question and never offered a single button to press.&lt;/p&gt;

&lt;p&gt;The server was fine. Nothing ran out of memory, nothing timed out. The game was doing exactly what I had told it to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a room works
&lt;/h2&gt;

&lt;p&gt;Each game is one of Cloudflare's Durable Objects, addressed by the six-digit PIN on the projector. Every phone in the room opens a WebSocket to that one object, and that object is the only place the game exists.&lt;/p&gt;

&lt;p&gt;A Durable Object handles one event at a time. A hall full of people answering in the same second cannot corrupt the scores, because there is never a second thread to race against. There are no locks in the code because there is nothing for them to protect.&lt;/p&gt;

&lt;p&gt;There is also no shared database. The room keeps its own state in the object's built-in storage: the players, their scores, the question in flight. That is what lets a room survive being evicted from memory and pick up where it was. When the game ends, an alarm deletes the room's data. Each game is its own small database, and it lives exactly as long as the game.&lt;/p&gt;

&lt;p&gt;Answers arrive in bursts, so broadcasts are batched, at most four a second, instead of one per answer. Idle sockets use WebSocket Hibernation, so a quiet room costs nothing. It runs on Cloudflare's free plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule that was right on paper
&lt;/h2&gt;

&lt;p&gt;The game has knockout rounds. Get a question wrong and you are out. So I wrote a rule for late joiners that seemed obvious: if you join after the game has started, you watch. You cannot walk into a knockout halfway through and claim you survived questions you never saw.&lt;/p&gt;

&lt;p&gt;In a test, that rule never fires. Everyone is already in the lobby when you press Start, because you are the one deciding when to press it.&lt;/p&gt;

&lt;p&gt;A real lecture hall does not work like that. People are still walking in, still finding the QR code, still typing a name, when the host decides the room looks full enough. The host pressed Start with about 45 people in. Every phone that finished joining a second later was a spectator, for the whole game.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing it while it was running
&lt;/h2&gt;

&lt;p&gt;We kept the event going. Whoever had been stranded was carried into the next round by hand, so nobody lost their place for something that was not their fault.&lt;/p&gt;

&lt;p&gt;Meanwhile I changed the rule, and deployed it during the event. In a round where nobody can be eliminated, a latecomer now joins as a full player immediately. In a knockout round they watch the current question and come in alive at the next one, so nobody is knocked out by a question they never saw. The only thing that keeps someone out for good is an actual elimination.&lt;/p&gt;

&lt;p&gt;The part I am most glad of: anyone already stuck as a spectator did not have to do anything. When the next question started, the server brought them back in. By the following round, most of the room was playing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two players who were knocked out
&lt;/h2&gt;

&lt;p&gt;Two players were knocked out who should not have been, and by the end of the event I did not know why.&lt;/p&gt;

&lt;p&gt;It turned out not to be the server at all. Both had switched away from the tab in the middle of the game. When they came back, the phone reloaded the page, and in a knockout round that cost them their place.&lt;/p&gt;

&lt;p&gt;That is the other half of the same lesson. A phone is not a test browser. It suspends tabs it is not showing, it reloads them when it wants the memory back, and nobody in a lecture hall keeps one tab open for an hour.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I took from it
&lt;/h2&gt;

&lt;p&gt;The architecture held. One object per room, no shared state, a single thread: none of that was the problem, and none of it needed to change.&lt;/p&gt;

&lt;p&gt;What failed was an assumption about people. Practice is not the same as the real thing, and the difference is never in the parts you tested. It is the queue at the door, and the tab someone switched away from.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;First published on &lt;a href="https://davidmashiah.com/notes/the-room-filled-after-i-pressed-start" rel="noopener noreferrer"&gt;davidmashiah.com&lt;/a&gt;, with the rest of my notes on real-time systems, machine learning reliability and supply chains.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>scalability</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
