<?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: flurin laim</title>
    <description>The latest articles on DEV Community by flurin laim (@flurin_laim_2f8fe184bcbd1).</description>
    <link>https://dev.to/flurin_laim_2f8fe184bcbd1</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%2F4100757%2Fb29f069f-3b88-4cfc-bc8d-5281cc99b7a3.png</url>
      <title>DEV Community: flurin laim</title>
      <link>https://dev.to/flurin_laim_2f8fe184bcbd1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/flurin_laim_2f8fe184bcbd1"/>
    <language>en</language>
    <item>
      <title>Why a ticket-availability monitor is a state machine, not a scraper</title>
      <dc:creator>flurin laim</dc:creator>
      <pubDate>Sat, 29 Aug 2026 21:16:14 +0000</pubDate>
      <link>https://dev.to/flurin_laim_2f8fe184bcbd1/why-a-ticket-availability-monitor-is-a-state-machine-not-a-scraper-95o</link>
      <guid>https://dev.to/flurin_laim_2f8fe184bcbd1/why-a-ticket-availability-monitor-is-a-state-machine-not-a-scraper-95o</guid>
      <description>&lt;p&gt;A ticket calendar looks like an easy automation target: request a page, search&lt;br&gt;
for a date, and send an email when it appears. That implementation works until&lt;br&gt;
the first queue, partial response, stale cache or provider outage. Then it can&lt;br&gt;
quietly turn "I do not know" into "sold out" — or generate a false alert.&lt;/p&gt;

&lt;p&gt;I learned this while building&lt;br&gt;
&lt;a href="https://machuping.com/availability-monitor" rel="noopener noreferrer"&gt;MachuPing&lt;/a&gt;, an independent monitor&lt;br&gt;
for official Machu Picchu ticket availability. I am the maker. It does not&lt;br&gt;
sell, hold, reserve or buy admission; the official booking platform remains the&lt;br&gt;
source of truth.&lt;/p&gt;

&lt;p&gt;The useful abstraction is a small state machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UNKNOWN -&amp;gt; CONFIRMED_UNAVAILABLE -&amp;gt; RETURNED_AVAILABLE
   ^                 |                       |
   |                 v                       v
   +------------- PROVIDER_ERROR ------ ALERTED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact labels will vary, but three rules matter.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Unknown is not unavailable
&lt;/h3&gt;

&lt;p&gt;Queues, timeouts, malformed payloads and incomplete calendars are observations&lt;br&gt;
about the monitor, not evidence about inventory. Persist them separately. A&lt;br&gt;
provider error should never close a date or trigger a reassuring "still sold&lt;br&gt;
out" message.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Match the user's real constraint
&lt;/h3&gt;

&lt;p&gt;"Machu Picchu is available" is too broad to be useful. Inventory is split by&lt;br&gt;
route, date, entry time and capacity. A valid transition requires a match for&lt;br&gt;
the selected combination, including the requested party size.&lt;/p&gt;

&lt;p&gt;This also prevents a common analytics mistake: counting every polling response&lt;br&gt;
or every seat-like value as a unique ticket. A state change is a state change,&lt;br&gt;
not proof of inventory volume.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Alert on a confirmed transition, not a snapshot
&lt;/h3&gt;

&lt;p&gt;The valuable event is not simply &lt;code&gt;available&lt;/code&gt;. It is a move from a previously&lt;br&gt;
confirmed unavailable state to confirmed available. Persist an idempotency key&lt;br&gt;
for that combination so retries do not create duplicate email.&lt;/p&gt;

&lt;p&gt;Before sending, revalidate the observation when the provider permits it. The&lt;br&gt;
alert should still state the limitation plainly: availability can disappear&lt;br&gt;
before the traveller reaches official checkout.&lt;/p&gt;
&lt;h3&gt;
  
  
  A practical event record
&lt;/h3&gt;

&lt;p&gt;At a module boundary, I prefer an explicit shape similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AvailabilityObservation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;attractionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;visitDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;entryTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;partySize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;available&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unavailable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unknown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;observedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;official-provider&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The monitoring loop can then compare the new observation with the last&lt;br&gt;
confirmed state, while the alert layer consumes only a narrowly defined&lt;br&gt;
&lt;code&gt;returned_available&lt;/code&gt; event.&lt;/p&gt;

&lt;p&gt;That separation makes the system less exciting in a demo and much safer in&lt;br&gt;
production. It also generalizes beyond tickets: appointment slots, permits,&lt;br&gt;
limited reservations and restocks all benefit from treating uncertainty as a&lt;br&gt;
first-class state.&lt;/p&gt;

&lt;p&gt;If you have built a monitor against a fragile upstream calendar, I would be&lt;br&gt;
interested in the failure mode that forced you to stop treating it as a simple&lt;br&gt;
scrape.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>saas</category>
      <category>monitoring</category>
      <category>sre</category>
    </item>
  </channel>
</rss>
