<?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: Debjit Dey</title>
    <description>The latest articles on DEV Community by Debjit Dey (@debjit450).</description>
    <link>https://dev.to/debjit450</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%2F3579460%2Fbd6fc51d-2749-4bb9-9ba8-46d8bce33f74.jpg</url>
      <title>DEV Community: Debjit Dey</title>
      <link>https://dev.to/debjit450</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/debjit450"/>
    <language>en</language>
    <item>
      <title>Tracking Chaos: Building a Real-Time Flight Anomaly Engine with Django, Celery, and Machine Learning</title>
      <dc:creator>Debjit Dey</dc:creator>
      <pubDate>Sun, 24 May 2026 11:25:09 +0000</pubDate>
      <link>https://dev.to/debjit450/tracking-chaos-building-a-real-time-flight-anomaly-engine-with-django-celery-and-machine-learning-4gcb</link>
      <guid>https://dev.to/debjit450/tracking-chaos-building-a-real-time-flight-anomaly-engine-with-django-celery-and-machine-learning-4gcb</guid>
      <description>&lt;p&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%2F5woluxa32gvn1bucpc86.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%2F5woluxa32gvn1bucpc86.png" alt=" " width="800" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine walking outside on a quiet afternoon. You hear a sharp roar overhead, pull out your phone, and open a flight-tracking app. You find a tiny airplane icon ✈️ iding smoothly along a solid line. It looks clean, structured, and completely predictable.&lt;/p&gt;

&lt;p&gt;But what if that airplane icon suddenly starts making frantic, tight loops over a residential area? What if it begins a terrifyingly rapid descent, or behaves in a way that defies normal flight paths?&lt;/p&gt;

&lt;p&gt;If a human air traffic controller isn’t watching that specific screen, how can software automatically flag that something is wrong?&lt;/p&gt;

&lt;p&gt;When I set out to build &lt;strong&gt;SkyWatch Live&lt;/strong&gt;, an open-source airspace and satellite tracking dashboard, my focus quickly shifted from simply drawing dots on a map to a much more interesting engineering problem: &lt;strong&gt;How do you build a real-time machine learning pipeline that can detect unusual airborne behavior across thousands of concurrent flights using chaotic public data?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/debjit450/skywatch-live" rel="noopener noreferrer"&gt;https://github.com/debjit450/skywatch-live&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whether you are an AI engineer or someone who has never looked at aviation data in your life, the architecture behind processing volatile, high-frequency telemetry into clean, explainable alerts contains lessons that apply to any real-time streaming system.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Operational Blueprint
&lt;/h2&gt;

&lt;p&gt;Before diving into the math, it helps to see the pipeline that keeps everything alive. The application runs a split architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The UI Layer:&lt;/strong&gt; A &lt;strong&gt;React 19&lt;/strong&gt; and &lt;strong&gt;TanStack Start&lt;/strong&gt; dashboard using &lt;strong&gt;MapLibre GL&lt;/strong&gt; and &lt;strong&gt;deck.gl&lt;/strong&gt; to paint real-time positions and historical playback tracks smoothly at 60 frames per second.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Ingestion &amp;amp; Inference Layer:&lt;/strong&gt; A &lt;strong&gt;Django ASGI&lt;/strong&gt; core backed by &lt;strong&gt;Celery background workers&lt;/strong&gt;, a fast &lt;strong&gt;Redis&lt;/strong&gt; state cache, and a durable &lt;strong&gt;PostgreSQL&lt;/strong&gt; time-series database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every 15 seconds, a scheduled Celery Beat task pulls raw telemetry vectors from multiple fragmented public radio networks. It de-duplicates them, caches the latest snapshot in Redis, and broadcasts them down a live WebSocket channel directly to the map.&lt;/p&gt;

&lt;p&gt;But as soon as that data hits the database, a post-commit hook hands the raw flight data over to our dedicated machine learning pipeline.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 3-Gate Anomaly Pipeline
&lt;/h2&gt;

&lt;p&gt;If you feed raw, noisy public data straight into a complex neural network, your system will instantly drown in false positives. External sensors glitch, transponders experience signal dropouts, and rate limits throttle incoming coordinates.&lt;/p&gt;

&lt;p&gt;To prevent false alarms, SkyWatch Live runs data through three computational gates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gate 1: Deterministic Physical Rules
&lt;/h3&gt;

&lt;p&gt;The first line of defense doesn't use AI at all. It uses fast, binary checks written in raw Python to catch immediate high-signal events:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Emergency Squawk Codes:&lt;/strong&gt; Radio transponders broadcasting specific numbers like &lt;code&gt;7700&lt;/code&gt; (general emergency) or &lt;code&gt;7600&lt;/code&gt; (radio communication failure).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kinematic Violations:&lt;/strong&gt; Physical impossibilities, such as a non-military cargo plane suddenly executing a 90-degree turn mid-air or dropping altitude faster than its structural limits allow.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Gate 2: Feature Engineering &amp;amp; Spatial Grids
&lt;/h3&gt;

&lt;p&gt;If a flight path passes basic physics checks, the pipeline extracts hidden behavioral features out of raw coordinate sequences (&lt;code&gt;latitude&lt;/code&gt;, &lt;code&gt;longitude&lt;/code&gt;, &lt;code&gt;altitude&lt;/code&gt;, &lt;code&gt;heading&lt;/code&gt;, &lt;code&gt;velocity&lt;/code&gt;). This happens inside &lt;code&gt;backend/ml/features.py&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Spatial Indexing:&lt;/strong&gt; The engine dynamically hashes coordinate points into a geometric grid to calculate &lt;em&gt;local proximity metrics&lt;/em&gt; (spotting close-proximity events or dense airspace deviations).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Angular Velocity Tracking:&lt;/strong&gt; By computing statistical variance across rolling windows of an aircraft's heading history, the system converts raw directional degrees into a "loitering score" that exposes circling or tracking patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Behavioral Baseline:&lt;/strong&gt; The telemetry is cross-referenced with a historical &lt;code&gt;AircraftProfile&lt;/code&gt; table, checking whether the current aircraft type is operating outside its typical operational envelope.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Gate 3: The Statistical Machine Learning Ensemble
&lt;/h3&gt;

&lt;p&gt;Once the features are compiled into a normalized vector, they strike a three-model ensemble powered by &lt;code&gt;scikit-learn&lt;/code&gt;. Using a blend of different algorithmic approaches balances out the blind spots of any single model:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Isolation Forest:&lt;/strong&gt; A tree-based model that isolates anomalies by randomly partitioning features. Because anomalies require fewer splits to isolate than normal data, they appear near the shallow roots of the trees. It is great for spotting overall global outliers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local Outlier Factor (LOF):&lt;/strong&gt; A density-based algorithm that measures how locally isolated a data point is relative to its surrounding neighborhood. This catches contextual anomalies—like a plane flying at a speed that is normal globally, but highly irregular for that specific crowded corridor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MLP Autoencoder:&lt;/strong&gt; A neural network that attempts to compress the multi-dimensional feature vector down into a tiny bottleneck layer and reconstruct it perfectly on the other side.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The autoencoder flags structural anomalies by calculating the &lt;strong&gt;Mean Squared Error (MSE)&lt;/strong&gt; reconstruction error between the original feature vector x and the reconstructed output x̂ across n dimensions:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flatex.codecogs.com%2Fpng.image%3F%5Cdpi%7B120%7DE%3D%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%28x_i-%5Chat%7Bx%7D_i%29%5E2" 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%2Flatex.codecogs.com%2Fpng.image%3F%5Cdpi%7B120%7DE%3D%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%28x_i-%5Chat%7Bx%7D_i%29%5E2" alt="MSE Formula" width="170" height="54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the structural configuration of a flight path is weird, the autoencoder fails to reconstruct it accurately, causing the error E to spike beyond a dynamic, self-calibrating threshold.&lt;/p&gt;




&lt;h2&gt;
  
  
  Going Deeper: Time-Series Sequence Analysis
&lt;/h2&gt;

&lt;p&gt;While spatial snapshots catch immediate deviations, flight data is fundamentally a time-dependent sequence. To track subtle, slow-building irregularities over time, SkyWatch Live features an optional deep learning path using a Long Short-Term Memory (&lt;strong&gt;LSTM&lt;/strong&gt;) network inside &lt;code&gt;backend/ml/lstm.py&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[State at t-3] ──► [State at t-2] ──► [State at t-1] ──► [Current State t]
                                                               │
                                                               ▼
                                                    Deep Sequence Inference
                                                               │
                                                               ▼
                                                    Trajectory Anomaly Score

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Engineering for Accessibility:&lt;/strong&gt; TensorFlow and Keras are intentionally excluded from the project's default dependency file. This ensures open-source contributors can download, run, and modify the UI or standard ingestion loops without requiring massive deep-learning runtimes or expensive GPUs. The LSTM modules load conditionally, initializing only when a user explicitly activates them via &lt;code&gt;python manage.py train_lstm_anomaly&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Explainability: Busting the "Black Box"
&lt;/h2&gt;

&lt;p&gt;An anomaly alert is completely useless if a user doesn't know why it went off. If the map flashes red, an operator needs to know what triggered the alarm instantly.&lt;/p&gt;

&lt;p&gt;To fix this, our explainability module decomposes the ensemble's mathematical scoring matrix into an explicit plain-text payload. When the UI hits &lt;code&gt;/api/v1/anomalies/&amp;lt;id&amp;gt;/explanation/&lt;/code&gt;, it receives a clean breakdown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"anomaly_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8f3b2a-7c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"detector_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ensemble_LOF"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"severity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CRITICAL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"confidence_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.91&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"explanation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Triggered due to an 87% deviation in rolling heading variance (circling behavior) paired with atypical low-velocity thresholds for this airframe profile."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frontend reads this payload to display clear warnings alongside the live flight profile. Users can even submit structured feedback to mark a detection as a false alarm, creating a clean, labeled dataset that our automated Celery jobs use to retrain the models every week.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building Systems That Expect Uncertainty
&lt;/h2&gt;

&lt;p&gt;SkyWatch Live shows that you can build highly performant, intelligent monitoring tools out of raw public data if you architect your pipeline to expect imperfections. By separating your fast live-state caches from your analytical data stores and guarding your machine learning models with strict validation layers, you build a system that tells the truth about chaotic real-world inputs.&lt;/p&gt;

&lt;p&gt;If you have a laptop, a curious mindset, and want to dig into the background tasks, training engines, or the mapping layer, the repository is open source and ready for setup. Hop into the codebase, explore how the real-time data flows, and let me know your thoughts!&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/debjit450/skywatch-live" rel="noopener noreferrer"&gt;debjit450/skywatch-live&lt;/a&gt;&lt;/p&gt;




</description>
      <category>django</category>
      <category>react</category>
      <category>machinelearning</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Adaptive Rate Limiting with Redis and Lua</title>
      <dc:creator>Debjit Dey</dc:creator>
      <pubDate>Tue, 28 Apr 2026 17:36:33 +0000</pubDate>
      <link>https://dev.to/debjit450/adaptive-rate-limiting-with-redis-and-lua-32fe</link>
      <guid>https://dev.to/debjit450/adaptive-rate-limiting-with-redis-and-lua-32fe</guid>
      <description>&lt;p&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%2Ft88bw7nx2suua8v7j1d4.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%2Ft88bw7nx2suua8v7j1d4.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Making Rate Limiting Correct Under Concurrency
&lt;/h2&gt;

&lt;p&gt;Most rate limiting tutorials stop at the single-instance case.&lt;br&gt;
That’s fine for learning, but it breaks quickly in production.&lt;/p&gt;

&lt;p&gt;Once you have multiple instances and real traffic patterns, the problem changes.&lt;br&gt;
It’s no longer just about picking an algorithm — it’s about &lt;strong&gt;correctness under concurrency&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article walks through what actually goes wrong and how to fix it.&lt;/p&gt;


&lt;h2&gt;
  
  
  The In-Memory Trap
&lt;/h2&gt;

&lt;p&gt;The first implementation most people write looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep a counter in memory&lt;/li&gt;
&lt;li&gt;increment on each request&lt;/li&gt;
&lt;li&gt;reject when the limit is reached&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This works perfectly in a single instance.&lt;/p&gt;

&lt;p&gt;Now deploy two instances.&lt;/p&gt;

&lt;p&gt;Each instance has its own counter. A client can exceed your intended limit just by hitting different instances.&lt;/p&gt;

&lt;p&gt;At that point, you don’t have a rate limiter anymore.&lt;br&gt;
You have a suggestion.&lt;/p&gt;


&lt;h2&gt;
  
  
  Redis Fixes Distribution, Not Concurrency
&lt;/h2&gt;

&lt;p&gt;The next step is moving state to Redis.&lt;/p&gt;

&lt;p&gt;Now all instances share the same counters. Good.&lt;/p&gt;

&lt;p&gt;A typical implementation looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read current count from Redis&lt;/li&gt;
&lt;li&gt;Check against limit&lt;/li&gt;
&lt;li&gt;Increment and write back&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This seems correct, but it isn’t.&lt;/p&gt;

&lt;p&gt;These are separate operations. Under concurrent load:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;two requests read the same value&lt;/li&gt;
&lt;li&gt;both pass the check&lt;/li&gt;
&lt;li&gt;both increment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now your limit is no longer strict. It’s approximate.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Real Problem: Atomicity
&lt;/h2&gt;

&lt;p&gt;The issue isn’t Redis.&lt;/p&gt;

&lt;p&gt;It’s that the decision is split across multiple steps.&lt;/p&gt;

&lt;p&gt;What you need is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a single, atomic operation that reads state, applies logic, and updates state&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  The Fix: Lua Scripts in Redis
&lt;/h2&gt;

&lt;p&gt;Redis supports Lua scripts that execute atomically.&lt;/p&gt;

&lt;p&gt;No other command runs between the start and end of the script.&lt;/p&gt;

&lt;p&gt;Instead of multiple round trips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;read state&lt;/li&gt;
&lt;li&gt;apply limiter logic&lt;/li&gt;
&lt;li&gt;update state&lt;/li&gt;
&lt;li&gt;return decision&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You do everything inside one script.&lt;/p&gt;

&lt;p&gt;Example (simplified):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;KEYS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;tonumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nb"&gt;tonumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ARGV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"INCR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;KEYS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"EXPIRE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;KEYS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;ARGV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no race conditions&lt;/li&gt;
&lt;li&gt;consistent decisions across instances&lt;/li&gt;
&lt;li&gt;predictable behavior under load&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Where Algorithms Fit In
&lt;/h2&gt;

&lt;p&gt;At this point, you can plug in different strategies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Token Bucket → allows bursts, smooths over time&lt;/li&gt;
&lt;li&gt;Sliding Window → more accurate but heavier&lt;/li&gt;
&lt;li&gt;Leaky Bucket → enforces steady flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But here’s the key point:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The algorithm matters less than where the decision happens.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If your logic isn’t atomic, the algorithm won’t save you.&lt;/p&gt;




&lt;h2&gt;
  
  
  Static Limits Miss Real Traffic Behavior
&lt;/h2&gt;

&lt;p&gt;Even with correct enforcement, static limits are too rigid.&lt;/p&gt;

&lt;p&gt;Real traffic looks like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;legitimate bursts&lt;/li&gt;
&lt;li&gt;scrapers probing endpoints&lt;/li&gt;
&lt;li&gt;repeated identical requests&lt;/li&gt;
&lt;li&gt;denial loops&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A fixed limit treats all of these the same.&lt;/p&gt;




&lt;h2&gt;
  
  
  Adding a Behavior Layer
&lt;/h2&gt;

&lt;p&gt;A simple improvement is to track short-term behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;request volume over a short window (burst detection)&lt;/li&gt;
&lt;li&gt;repeated request fingerprints&lt;/li&gt;
&lt;li&gt;number of unique routes hit (scan detection)&lt;/li&gt;
&lt;li&gt;repeated denials&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This produces a basic risk score.&lt;/p&gt;

&lt;p&gt;That score maps to tiers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;normal&lt;/li&gt;
&lt;li&gt;elevated&lt;/li&gt;
&lt;li&gt;suspicious&lt;/li&gt;
&lt;li&gt;blocked&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important part is separation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Limiter&lt;/strong&gt; → enforces limits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy&lt;/strong&gt; → decides how strict to be&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This keeps the system easier to reason about and tune.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tradeoffs
&lt;/h2&gt;

&lt;p&gt;This approach is not free.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lua scripts add complexity&lt;/li&gt;
&lt;li&gt;debugging moves closer to Redis&lt;/li&gt;
&lt;li&gt;Redis becomes a critical dependency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But for systems that need consistency under concurrency, the tradeoff is worth it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;The biggest lesson is not about token buckets or sliding windows.&lt;/p&gt;

&lt;p&gt;It’s this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Correctness in rate limiting comes from atomic decision-making.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you ensure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a single source of truth&lt;/li&gt;
&lt;li&gt;atomic execution&lt;/li&gt;
&lt;li&gt;consistent state across instances&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;the rest becomes much easier.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;I built this approach into a small system to explore the problem end-to-end.&lt;/p&gt;

&lt;p&gt;If you’re interested in seeing a full implementation (TypeScript + Redis + Lua), you can check it out here:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/debjit450/arce" rel="noopener noreferrer"&gt;https://github.com/debjit450/arce&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you’ve dealt with this problem in production, I’d be interested to hear how you approached it.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>distributedsystems</category>
      <category>systemdesign</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>StableJSON: A Practical Workspace for Serious JSON Work</title>
      <dc:creator>Debjit Dey</dc:creator>
      <pubDate>Wed, 31 Dec 2025 06:14:37 +0000</pubDate>
      <link>https://dev.to/debjit450/stablejson-a-practical-workspace-for-serious-json-work-2cal</link>
      <guid>https://dev.to/debjit450/stablejson-a-practical-workspace-for-serious-json-work-2cal</guid>
      <description>&lt;p&gt;JSON is everywhere — APIs, configs, logs, exports, payloads, diffs.&lt;br&gt;
If you build software, you already spend a non-trivial part of your life working with it.&lt;/p&gt;

&lt;p&gt;Most JSON tools fall into two camps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Too basic&lt;/strong&gt; — format and validate, then you’re on your own&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overengineered&lt;/strong&gt; — cluttered UIs, half-useful features, slow workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;StableJSON sits in between.&lt;br&gt;
It’s a focused workspace for &lt;em&gt;actually working with JSON&lt;/em&gt;, not just prettifying it.&lt;/p&gt;

&lt;p&gt;Live app: &lt;a href="https://stablejson.vercel.app" rel="noopener noreferrer"&gt;https://stablejson.vercel.app&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/debjit450/stablejson" rel="noopener noreferrer"&gt;https://github.com/debjit450/stablejson&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Formatting Isn’t the Hard Part
&lt;/h2&gt;

&lt;p&gt;Pretty-printing JSON is solved. Every editor can do that.&lt;/p&gt;

&lt;p&gt;The real problems show up when you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compare large API responses&lt;/li&gt;
&lt;li&gt;Debug payload mismatches&lt;/li&gt;
&lt;li&gt;Clean data before storage or hashing&lt;/li&gt;
&lt;li&gt;Generate types from unknown or evolving structures&lt;/li&gt;
&lt;li&gt;Ensure identical data always produces identical output&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s where things usually break down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Key order changes&lt;/li&gt;
&lt;li&gt;Nulls and empty values add noise&lt;/li&gt;
&lt;li&gt;Diffs become unreadable&lt;/li&gt;
&lt;li&gt;Hashes change unexpectedly&lt;/li&gt;
&lt;li&gt;Generated types drift from reality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;StableJSON is built specifically around these failure points.&lt;/p&gt;




&lt;h2&gt;
  
  
  What StableJSON Actually Gives You
&lt;/h2&gt;

&lt;p&gt;StableJSON is a browser-based JSON workspace with tools that cover the &lt;em&gt;entire&lt;/em&gt; JSON workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Validate &amp;amp; format&lt;/strong&gt; JSON with proper indentation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clean null, undefined, and empty values&lt;/strong&gt; in one step&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Side-by-side JSON diff&lt;/strong&gt; with clear highlighted changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Path inspection &amp;amp; extraction&lt;/strong&gt; for deeply nested data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automatic TypeScript interface and Zod schema generation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Canonical JSON output&lt;/strong&gt; for consistent hashing and comparison&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSONPath queries&lt;/strong&gt; to slice complex objects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structure analysis&lt;/strong&gt; (depth, size, data types)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transform, flatten, and reshape&lt;/strong&gt; JSON safely&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom validation rules&lt;/strong&gt; when default checks aren’t enough&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s not a collection of random utilities — it’s one coherent workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Canonical JSON Is the Quiet Power Feature
&lt;/h2&gt;

&lt;p&gt;One of the most important features in StableJSON is canonical output.&lt;/p&gt;

&lt;p&gt;When JSON is deterministic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hashes stop changing randomly&lt;/li&gt;
&lt;li&gt;Cache keys become reliable&lt;/li&gt;
&lt;li&gt;Diffs stay readable&lt;/li&gt;
&lt;li&gt;CI checks stop failing for no apparent reason&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’ve ever had two JSON objects that &lt;em&gt;look&lt;/em&gt; identical but serialize differently, you already know why this matters.&lt;/p&gt;

&lt;p&gt;Canonical output isn’t flashy — but it prevents entire classes of bugs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who This Is Built For
&lt;/h2&gt;

&lt;p&gt;StableJSON is for developers who:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debug APIs regularly&lt;/li&gt;
&lt;li&gt;Care about correctness, not just visuals&lt;/li&gt;
&lt;li&gt;Work with large or dynamic JSON structures&lt;/li&gt;
&lt;li&gt;Need reliable diffs, hashes, and generated types&lt;/li&gt;
&lt;li&gt;Want one tool instead of five scattered ones&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If JSON is part of your daily workflow, this tool earns its keep very quickly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;Most JSON tools stop at “looks nice”.&lt;/p&gt;

&lt;p&gt;StableJSON goes further — it helps you &lt;strong&gt;understand&lt;/strong&gt;, &lt;strong&gt;compare&lt;/strong&gt;, &lt;strong&gt;clean&lt;/strong&gt;, and &lt;strong&gt;stabilize&lt;/strong&gt; your data.&lt;/p&gt;

&lt;p&gt;When you need JSON to be &lt;em&gt;right&lt;/em&gt;, not just readable, this is the tool you reach for.&lt;/p&gt;

&lt;p&gt;Try it: &lt;a href="https://stablejson.vercel.app" rel="noopener noreferrer"&gt;https://stablejson.vercel.app&lt;/a&gt;&lt;br&gt;
Explore the code: &lt;a href="https://github.com/debjit450/stablejson" rel="noopener noreferrer"&gt;https://github.com/debjit450/stablejson&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>devtool</category>
      <category>json</category>
    </item>
  </channel>
</rss>
