<?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: KenjiTanaka6849</title>
    <description>The latest articles on DEV Community by KenjiTanaka6849 (@kenjitanaka6849).</description>
    <link>https://dev.to/kenjitanaka6849</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%2F4063717%2F2a871b14-487c-44d2-ad5f-a89aef84a706.png</url>
      <title>DEV Community: KenjiTanaka6849</title>
      <link>https://dev.to/kenjitanaka6849</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kenjitanaka6849"/>
    <language>en</language>
    <item>
      <title>Kill switch for noisy uptime checks: a feature flag to disable a polling client</title>
      <dc:creator>KenjiTanaka6849</dc:creator>
      <pubDate>Thu, 06 Aug 2026 00:16:37 +0000</pubDate>
      <link>https://dev.to/kenjitanaka6849/kill-switch-for-noisy-uptime-checks-a-feature-flag-to-disable-a-polling-client-4d6n</link>
      <guid>https://dev.to/kenjitanaka6849/kill-switch-for-noisy-uptime-checks-a-feature-flag-to-disable-a-polling-client-4d6n</guid>
      <description>&lt;p&gt;Use a kill switch inside the checker when your uptime probes start amplifying an incident — one feature flag, read on every tick, that can disable the noisy checks and stop the retries at the source. Reach for tuned backoff and jitter instead when the retry storm stays inside a single process and never fans out onto a dependency somebody else is paging for.&lt;/p&gt;

&lt;p&gt;Both are cheap to build. Only one of them lets you quiet a polling client while its target is already on fire.&lt;/p&gt;

&lt;p&gt;I run cron and queue infrastructure, so most of my pages arrive as either "the job didn't run" or "the job ran four times." Health checking sits in the same family of problems: a small, frequent, automated request that multiplies badly when something upstream changes shape. What follows is the runbook I settled on after a fleet of pollers turned a non-incident into a real one — the failure mode, where the switch belongs, the implementation, and how to verify the flip before you walk away from the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually turns a polling client's uptime checks into a retry storm?
&lt;/h2&gt;

&lt;p&gt;Amplification. A single check is one request every 15 or 30 seconds, which nobody notices; a fleet of checks with retries layered on top is a synchronized load generator pointed at whatever you decided was important enough to monitor. The math is unkind. Take 40 instances, a 5s interval, and 3 retries per failed attempt, and a dependency that normally handles a trickle of health traffic suddenly sees a couple thousand requests a minute — all of them arriving at the exact moment it's least able to absorb them. Retries stack on top of the polling interval rather than replacing it, and because every poller sees the same failure at the same time, they all back off together and return together. The Google SRE book calls out this shape under cascading failures, and the load pattern that comes out of it looks nothing like organic traffic: sawtooth spikes, perfectly aligned, growing until something sheds load.&lt;/p&gt;

&lt;p&gt;The worst one I've dealt with wasn't even a real outage. Our checker read &lt;code&gt;status&lt;/code&gt; off the top level of a health payload, a routine change moved it under &lt;code&gt;checks[0].state&lt;/code&gt;, and the field I assumed was there came back as an empty string. Comparison against &lt;code&gt;"ok"&lt;/code&gt; never matched, so every probe in the fleet concluded the service was sick. The log line we emitted said &lt;code&gt;health check failed&lt;/code&gt; and nothing else — no field name, no body snippet, no status code. 38 pollers, 5s interval, 3 retries each, roughly 1,900 requests a minute against an endpoint that normally sees 120. The service was healthy the entire time. It took us about 25 minutes to work out that the fault was in the shape of the data, not the state of the system, and most of that time went into arguing about which deploy had "broken prod." I'm still not sure why we never logged the raw body on a parse miss; we do now.&lt;/p&gt;

&lt;p&gt;That's the case a kill switch is for. Not for hiding a real failure, but for cutting the amplifier when your own tooling has become the loudest client on the box.&lt;/p&gt;

&lt;h2&gt;
  
  
  Put the kill switch where the check runs, not where it's configured
&lt;/h2&gt;

&lt;p&gt;The instinct is to disable checks in the monitoring configuration — comment out the check, redeploy the config, move on. Mid-incident that's the wrong layer. Config lives on the deploy path, and the deploy path is exactly what you don't want to exercise while you're troubleshooting, because it's slow, it needs review, and it's a second source of change during an event you're already trying to explain.&lt;/p&gt;

&lt;p&gt;The switch belongs in the polling client, evaluated on each tick, with the last known value cached in memory.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Where the switch lives&lt;/th&gt;
&lt;th&gt;Time to take effect&lt;/th&gt;
&lt;th&gt;Blast radius&lt;/th&gt;
&lt;th&gt;Usable mid-incident&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Config file plus redeploy&lt;/td&gt;
&lt;td&gt;minutes to hours&lt;/td&gt;
&lt;td&gt;whole service&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Env var plus rolling restart&lt;/td&gt;
&lt;td&gt;minutes&lt;/td&gt;
&lt;td&gt;one deployment&lt;/td&gt;
&lt;td&gt;rarely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Feature flag read per tick&lt;/td&gt;
&lt;td&gt;one interval&lt;/td&gt;
&lt;td&gt;one check, one cohort&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Circuit breaker in the client&lt;/td&gt;
&lt;td&gt;milliseconds&lt;/td&gt;
&lt;td&gt;one dependency&lt;/td&gt;
&lt;td&gt;automatic, not aimable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A circuit breaker and a flag solve different halves of this. The breaker reacts in milliseconds to error rates it can measure locally, which is what you want for the common case; the flag is the aimable one, the thing a human points at a specific check when the automation's model of "healthy" is wrong. Run both.&lt;/p&gt;

&lt;p&gt;Two properties matter for the rollout. First, the flag decision has to be stable per probe: hash the probe ID into a bucket so that a 25% rollout means the same quarter of the fleet stays disabled tick after tick, rather than a random quarter each time — flapping suppression is worse than no suppression because it makes the graphs unreadable. Second, a flag fetch that doesn't land must keep the previous decision instead of reverting to a default. A safety valve that quietly re-arms itself when the flag store is unreachable isn't a safety valve.&lt;/p&gt;

&lt;h2&gt;
  
  
  The safe implementation: one flag read per tick
&lt;/h2&gt;

&lt;p&gt;Here's the core of the Go poller we run. The ticker is the retry — one attempt per interval, no inner retry loop, because an inner loop is how you turn a 15s cadence into a 3s cadence without anyone noticing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"hash/fnv"&lt;/span&gt;
    &lt;span class="s"&gt;"math/rand"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;UptimeChecksDisabled&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;   &lt;span class="s"&gt;`json:"uptime_checks_disabled"`&lt;/span&gt;
    &lt;span class="n"&gt;DisabledPercent&lt;/span&gt;      &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`json:"disabled_percent"`&lt;/span&gt; &lt;span class="c"&gt;// 0..100, cohort by probe ID&lt;/span&gt;
    &lt;span class="n"&gt;Reason&lt;/span&gt;               &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"reason"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;checker&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;probeID&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;
    &lt;span class="n"&gt;last&lt;/span&gt;    &lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="c"&gt;// last known decision; a fetch that doesn't land keeps it&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;checker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;loadFlags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRequestWithContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodGet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"http://flags.internal/state"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Shape changed under us. Keep the decision we already had and say so.&lt;/span&gt;
        &lt;span class="n"&gt;logDecode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;probeID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Stable cohort: the same probe lands in the same bucket every tick.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;inCohort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;probeID&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;percent&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fnv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New32a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;probeID&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sum32&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="m"&gt;100&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;percent&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;checker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loadFlags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&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;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UptimeChecksDisabled&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;inCohort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;probeID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisabledPercent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Silence is ambiguous. Emit a heartbeat so "suppressed" and "dead poller" look different.&lt;/span&gt;
        &lt;span class="n"&gt;heartbeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;probeID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"suppressed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reason&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="n"&gt;probeOnce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;checker&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;probeID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hostProbeID&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Timeout&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;// Jitter, so a fleet-wide restart doesn't align every poller on the same second.&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&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;&lt;code&gt;heartbeat&lt;/code&gt;, &lt;code&gt;probeOnce&lt;/code&gt;, &lt;code&gt;logDecode&lt;/code&gt; and &lt;code&gt;hostProbeID&lt;/code&gt; are elided; the only interesting thing about them is that the heartbeat fires whether or not the probe ran. Our Node.js pollers implement the same contract — same flag names, same heartbeat, same one-attempt-per-tick rule — because two different meanings of "disabled" across one fleet is how half your probes keep hammering after you thought you'd stopped them.&lt;/p&gt;

&lt;p&gt;One more habit from queue work: make the alert side idempotent too. If the alert dispatcher keys on check name plus a coarse time bucket, a suppressed check that comes back doesn't replay a backlog of notifications at whoever is holding the pager.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify the flip, then plan the way back
&lt;/h2&gt;

&lt;p&gt;Flipping the switch is the easy part. Confirming it did what you meant takes about three minutes and saves the argument later, so I do it in a fixed order: request rate at the target should drop within one polling interval, the suppressed heartbeat should appear for exactly the cohort you aimed at, and at least one canary probe should still be reporting so you haven't traded noise for blindness. If the rate doesn't move, the usual causes are a poller that caches flags for longer than its interval, a second checker nobody remembered (ours lived in a synthetic-monitoring job on a different schedule), or a cohort percentage that rounds to fewer instances than you expected.&lt;/p&gt;

&lt;p&gt;The way back deserves as much thought as the way out.&lt;/p&gt;

&lt;p&gt;Re-enabling a suppressed fleet all at once is its own thundering herd, so walk the percentage down in steps and watch the target's latency between them. Put an expiry on the flag with an owner attached — a kill switch with no removal date turns into permanent, undocumented blindness, and six months later nobody can tell you whether that check was retired on purpose. Write the flag name and the flip time into the incident timeline while you're at it. Half of postmortem archaeology is working out which suppression was still active when the next thing broke.&lt;/p&gt;

&lt;h2&gt;
  
  
  When a flag is the wrong tool
&lt;/h2&gt;

&lt;p&gt;If the checks are noisy because the threshold is wrong, fix the threshold; a kill switch just moves the bad signal out of view and the trade-off is that you'll rediscover it during the next incident. Flags are also not suitable when the amplification needs sub-second correction, or when the checker can't reach the flag store from wherever it runs — stick with a client-side circuit breaker and a hard request budget for those. And if you find yourself adding a switch per check, that's a sign the monitoring surface itself needs pruning rather than more toggles.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Google SRE Book — Monitoring Distributed Systems: &lt;a href="https://sre.google/sre-book/monitoring-distributed-systems/" rel="noopener noreferrer"&gt;https://sre.google/sre-book/monitoring-distributed-systems/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Google SRE Book — Addressing Cascading Failures: &lt;a href="https://sre.google/sre-book/addressing-cascading-failures/" rel="noopener noreferrer"&gt;https://sre.google/sre-book/addressing-cascading-failures/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AWS Builders' Library — Timeouts, retries, and backoff with jitter: &lt;a href="https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/" rel="noopener noreferrer"&gt;https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Martin Fowler — Feature Toggles (aka Feature Flags): &lt;a href="https://martinfowler.com/articles/feature-toggles.html" rel="noopener noreferrer"&gt;https://martinfowler.com/articles/feature-toggles.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>uptime</category>
      <category>monitoring</category>
      <category>sre</category>
      <category>go</category>
    </item>
  </channel>
</rss>
