<?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: Utkarsh Agarwal</title>
    <description>The latest articles on DEV Community by Utkarsh Agarwal (@utkarsh_agarwal_b9b79f7ed).</description>
    <link>https://dev.to/utkarsh_agarwal_b9b79f7ed</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%2F4164266%2F74c5e0f6-c56b-4c4e-8cd0-38a6a23144b7.jpg</url>
      <title>DEV Community: Utkarsh Agarwal</title>
      <link>https://dev.to/utkarsh_agarwal_b9b79f7ed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/utkarsh_agarwal_b9b79f7ed"/>
    <language>en</language>
    <item>
      <title>What Happens When a Reel Goes Viral: Queuing and Throttling 10,000 Instagram DMs Safely</title>
      <dc:creator>Utkarsh Agarwal</dc:creator>
      <pubDate>Mon, 05 Oct 2026 15:59:34 +0000</pubDate>
      <link>https://dev.to/utkarsh_agarwal_b9b79f7ed/what-happens-when-a-reel-goes-viral-queuing-and-throttling-10000-instagram-dms-safely-4pje</link>
      <guid>https://dev.to/utkarsh_agarwal_b9b79f7ed/what-happens-when-a-reel-goes-viral-queuing-and-throttling-10000-instagram-dms-safely-4pje</guid>
      <description>&lt;p&gt;Picture this. A creator posts a Reel that says "comment GUIDE and I'll send it to you." It does numbers. Within an hour, &lt;strong&gt;10,000 people comment&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If your automation was built for the demo, this is the moment it falls over.&lt;/p&gt;

&lt;p&gt;I've been building on the Instagram Graph API, and the happy path is easy: webhook in, DM out. The hard part is what happens when the happy path gets 10,000 times busier than you tested. Here's what I learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 1: Webhooks arrive in bursts, not a trickle
&lt;/h2&gt;

&lt;p&gt;When someone comments, Meta sends your server a webhook. When 10,000 people comment, Meta sends 10,000 webhooks in a very short window.&lt;/p&gt;

&lt;p&gt;The tempting first version does the work inside the request handler: look up the account, check the automation, write to the database, call the API to send the DM, then return 200.&lt;/p&gt;

&lt;p&gt;That falls over for two reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your database becomes the bottleneck. Every webhook opens connections and runs queries at exactly the rate Meta delivers events, not the rate you can handle.&lt;/li&gt;
&lt;li&gt;Slow responses trigger retries. Meta retries deliveries that time out or fail. A struggling server gets more traffic, not less. That's a retry storm, and it's how a slow minute becomes an outage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fix: do almost nothing in the handler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;webhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;valid_signature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;        &lt;span class="c1"&gt;# verify the HMAC signature first
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;entry&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;process_entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# hand off to a background worker
&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# ack immediately
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;(Simplified example, not production code.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Verify the signature, enqueue, return 200. The handler's job is to say "got it" quickly. Workers then drain the queue at whatever pace your system can sustain, no matter how fast events arrive.&lt;/p&gt;

&lt;p&gt;One more rule: be careful about returning errors under load. If your own database is struggling, a 5xx just invites a retry on top of the problem. Acknowledge, buffer, and recover.&lt;/p&gt;
&lt;h2&gt;
  
  
  Problem 2: Meta has limits, and they're not one number
&lt;/h2&gt;

&lt;p&gt;Sending a DM isn't unlimited. Depending on how you send, you can hit several different ceilings:&lt;/p&gt;

&lt;p&gt;Per-account hourly caps on how many DMs you can send as replies to comments.&lt;br&gt;
App-level usage limits shared across every account your app serves.&lt;br&gt;
The messaging window: automation is meant to respond to something the user did first, and replies live inside a time window.&lt;br&gt;
The app-level limit is the sneaky one. One viral creator can burn through capacity that every other customer depends on.&lt;/p&gt;

&lt;p&gt;Meta tells you how close you are. Graph API responses include an X-App-Usage header with usage percentages. Read it. Cache it. Then use it as a brake:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;safe_to_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;usage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app_usage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# refreshed from X-App-Usage
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;usage&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;call_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;SAFETY_MARGIN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;                        &lt;span class="c1"&gt;# app-wide: slow down for everyone
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;hourly_sent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;HOURLY_CAP&lt;/span&gt;

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

&lt;/div&gt;


&lt;p&gt;&lt;em&gt;(Simplified example. Pick your own margins and stay well under the documented limits instead of riding the edge.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A tip that sounds obvious and isn't: keep that usage reading fresh even when you're idle. If something else shares your app (a test script, a second environment), real usage can climb while your cache sits stale. A cheap periodic ping fixes it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Problem 3: What do you do when you're over the limit?
&lt;/h2&gt;

&lt;p&gt;You don't drop the message. You also don't hammer the API until it pushes back.&lt;/p&gt;

&lt;p&gt;You park it and retry later:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;safe_to_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;queued&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;          &lt;span class="c1"&gt;# park it, oldest first
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="nf"&gt;send_dm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A scheduled job picks queued items back up when the window resets, in the order they arrived. Oldest first matters: the person who commented first should get their DM first.&lt;/p&gt;

&lt;p&gt;The user-facing result: instead of "the automation broke", a creator sees "your DMs are sending in order and will finish shortly." That's an honest, calm experience, and it keeps accounts out of trouble.&lt;/p&gt;
&lt;h2&gt;
  
  
  Problem 4: Two workers, one trigger
&lt;/h2&gt;

&lt;p&gt;When you scale workers, you'll eventually have two of them pick up the same job. Without a guard, someone gets two DMs. Two identical DMs is the fastest way to look like spam.&lt;/p&gt;

&lt;p&gt;The fix is to claim the job atomically before doing any slow work:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;atomic&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;trigger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select_for_update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;trigger_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status__in&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pending&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;queued&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;                              &lt;span class="c1"&gt;# someone else already has it
&lt;/span&gt;    &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;processing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;# lock released; now do the slow API call
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Problem 5: Tokens expire and permissions get revoked
&lt;/h2&gt;

&lt;p&gt;Instagram access tokens don't last forever. Long-lived tokens last about 60 days and can be refreshed before they expire. Run a daily job that refreshes tokens approaching expiry, or automations will silently die weeks later.&lt;/p&gt;

&lt;p&gt;Users can also revoke access at any time. When the API returns an invalid-token error (code 190), stop sending for that account, mark it disconnected, and tell the user. Retrying a revoked token just generates noise and errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The checklist&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're building DM automation, here's what I'd do again&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Verify signatures, ack fast, queue everything. Do almost nothing in the webhook handler.&lt;/li&gt;
&lt;li&gt;Read X-App-Usage and slow down early. Stay well under limits, not at them.&lt;/li&gt;
&lt;li&gt;Queue, don't drop. Retry oldest-first when capacity returns.&lt;/li&gt;
&lt;li&gt;Claim jobs atomically. One trigger, one DM.&lt;/li&gt;
&lt;li&gt;Refresh tokens on a schedule and handle revocation cleanly.&lt;/li&gt;
&lt;li&gt;Only message people who engaged first. That's both Meta's rule and good product sense.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of this is glamorous. But the first time a post goes viral and your system quietly works through 10,000 comments without a single complaint, you'll be glad it's there.&lt;/p&gt;

&lt;p&gt;We build this at &lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://reachook.com/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdprtkj20u%2Fimage%2Fupload%2Fq_auto%2Ff_auto%2Fv1776254311%2Fog-image_kpsco4.jpg" height="800" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://reachook.com/" rel="noopener noreferrer" class="c-link"&gt;
            Instagram AI DM Automation &amp;amp; Comment Growth | Reachook
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Automate Instagram DMs &amp;amp; turn comments into leads 24/7 with Reachook's official Meta API platform. Boost creator sales effortlessly. Start free today!
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdprtkj20u%2Fimage%2Fupload%2Fq_auto%2Ff_auto%2Fv1776254318%2Fglobal_logo_ak3hwa.svg" width="435" height="435"&gt;
          reachook.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;,an DM automation platform built on Meta's official API. If you have questions about any of the above, drop them in the comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>api</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
