Build1 distinct publisher3 min readPublished
A dev.to post lists four ways the standard stop-the-dev-instances script fails past a few hundred instances. The one that produces an outage rather than a quiet leak is the ordering a flat list of instance IDs cannot express.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
Ordering only bites on the way up. Stopping three hundred instances in whatever sequence the API returns them is mostly harmless, because the work is going away anyway. The morning start is where the graph asserts itself: the app process comes up, finds nothing listening on the database, and exits, and a crash loop is that same process being restarted faster than its dependency becomes ready [3]. The post's prescription is storage, then compute, then application, with delays between tiers [4]. Delays are the weak part of that. A sleep is an open-loop guess about boot time; the primitive you want is a readiness check against the tier below, with a sleep as the fallback for when the check itself is unavailable. The lower tier can easily miss the window you guessed.
Discovery gives you a set of IDs; sequencing needs edges between them. The snippet shows the gap plainly. It filters on tag:env alone, with no instance-state filter and no pagination handling, then hands one flat list to stop_instances [2][16]. That shape never records what it intended to stop, so the silent-failure mode stays undetectable from inside the script [8].
The fifteen-instances figure is arithmetic on an assumption rather than a measurement; the post offers 5% as an illustration and does not report a rate it observed [17]. For the number to transfer you would need roughly three hundred tagged instances, a per-night stop failure rate near 5%, and no post-run check. The first two you cannot know without the third. Persist the intended ID set before the stop call, describe the instances again ten minutes later, and diff. The size of that diff is your number, and state-transition failures are exactly the ones that keep billing while still looking scheduled [9].
RDS earns its own line in the design. It stops through a different call, and a stopped instance restarts itself after seven days [10]. Held off for a year, that is 365 / 7, about 52 unrequested restarts per instance, each one billing until something notices and stops it again [13]. An evening schedule catches those the same night. A weekend-only schedule does not.
Worth holding in mind about the source: it closes by recommending ZopNight, a product built for this problem across resource types and clouds [12]. The four failure modes still hold up on their own merits, and the requirements list also reads like a product spec, with tag-driven discovery, timezone-aware schedules per environment, time-bounded overrides, and reconciliation with alerting as features being sold as well as features you need [14]. The list survives its provenance because each item maps to a failure you can reproduce. The single UTC cron is the easiest to reproduce: one global 20:00 either kills an environment in the middle of someone's afternoon or leaves it up all night [5].
The observation I would trust most is about human behaviour, not APIs. The post says the override problem breaks first for most teams, usually one badly timed shutdown during a release [15]. A schedule switched off "just for now" reliably costs you the savings it was supposed to deliver [6].
Ranked by verification strength, evidence, and original report placement.
The post's example script (stop_dev.py, triggered by EventBridge at 20:00) uses boto3 to call describe_instances with a filter on tag:env = dev, flattens every returned InstanceId into one list, and passes that list to a single stop_instances call.
The post states that app instances depend on databases, and that stopping them in random order means the app comes alive before the database is ready on restart and lands in a crash loop.
The post states that a flat list of instance IDs has no concept of 'start this after that', and that real scheduling needs dependency-aware sequencing of storage, then compute, then application, with delays between tiers.
The post states that a single UTC cron firing at 20:00 either shuts down an environment in the middle of a team's afternoon or leaves it running all night, and that schedules must be timezone-aware per environment or per team.
The post states the script has no memory of whether last night's shutdown ran, and that at three hundred instances a 5% silent failure rate means fifteen instances running 24/7 that you believe are scheduled, with nothing telling you; it prescribes reconciliation of scheduled-to-stop against actually-stopped, with alerting on the gap.
The post attributes failed stops to state transitions, and says the affected instances keep billing.
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 27, 2026
Follow any of these and your For You feed starts watching them — no settings page required.
build
Put a threshold and a price next to every "idle" resource, or stop calling it idle1 distinct publisher
build
S3 to Lambda is async and at-least-once: the 3% that vanished after eight quiet months1 distinct publisher
build
Two mechanisms, one vCPU floor: why db.t3.micro cannot meet a 1-second RPO on RDS1 distinct publisher
build
Cloud waste is a tagging habit, and that 76% shutdown number needs a second look1 distinct publisher
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
One script, no incident report
Everything rests on five lines of boto3 and careful reasoning about them. That is genuinely enough to establish what a flat list of instance IDs cannot express and why one cron has one clock. It is nowhere near enough to establish that 5% of stops fail, that anyone's savings actually evaporated, or that three hundred is where things break — there is no fleet, no postmortem, and no second publisher.
Nothing disclosed
No one says how many teams run scheduling this way, how many have moved off the DIY Lambda, or what either named tool is deployed against. ZopNight is recommended and AWS Instance Scheduler is acknowledged, both without a single customer, install or cost figure.
Sound mechanics, decorative numbers
The gap stays modest because the post never claims a measured result — the four mechanisms fall out of the code it prints. What widens it is the arithmetic dressed as finding, 5% of 300 becoming fifteen billing instances, plus a year-long disabled schedule told as if it were a case study, and then the pivot to a product name that turns a taxonomy into a buying reason.
Problem statement ends in a product name
The piece arrives as engineering and departs as marketing: six requirements are built up, then ZopNight is named as the thing built for exactly this across clouds, while AWS's free first-party scheduler is characterised mainly as something you have to run yourself. The technical grasp is real, which is what makes the shape worth naming — this is category marketing by someone who understands the category.
Trust the code, not the counts
Split verdict. High confidence in the mechanics — the listing, the ordering gap, the RDS instance that restarts itself after a week are all checkable. Low confidence in every magnitude, and no second account against which to test either. One post, one author, one product at the end of it.