Critical or non-critical: the failure contract of ECS daemons
Listen to article
generated on playGenerated only on first play
Powered by Amazon Polly + OmniVoice
On September 3, 2026 AWS started letting you declare an ECS Managed Daemon as non-critical, turning a decision that used to be implicit into a versioned parameter. What is at stake is not the daemon: it is the failure contract between a cross-cutting agent and the instance hosting it. This teardown dissects the anatomy of the pattern, the decision rule I use to classify each agent, and what you pay — in churn, in blind spots and in dollars — for classifying it wrong.
Every container cluster carries a layer of software nobody asked for and everybody needs: the log shipper, the EDR agent, the metrics exporter, the mesh proxy. For years that layer was treated as a packaging detail — one more sidecar in the task definition, a DaemonSet on Kubernetes. The launch of non-critical daemons in Amazon ECS Managed Daemons, on September 3, 2026, exposes the question that was hiding underneath the packaging: when that agent dies, what should happen to the machine hosting it? The answer is now a parameter (critical), and parameters get versioned, reviewed — and gotten wrong.
The problem: cross-cutting agents are coupling disguised as convenience
The sidecar-per-task model solves distribution and fails at economics and governance. An instance running 40 tasks runs 40 copies of the log shipper; at 128 MiB each, that is 5 GiB of RAM spent duplicating one function. Worse than the waste is the drift: the agent version becomes the property of each application team, and the security team finds out during an audit that three services still run a seven-month-old image.
ECS already had the DAEMON scheduling strategy for the EC2 launch type, but that is placement only — one daemon per instance, with no guarantee that it is up before the first application task serves traffic. For telemetry that is a hole in the graph. For a runtime security agent, it is a window in which the instance processes transactions without coverage.
Managed Daemons, GA on April 1, 2026 for ECS Managed Instances capacity providers, closed that hole by inverting the relationship: the instance only transitions the application task to RUNNING after the daemon is running. The price of that guarantee was rigid coupling — any daemon failure drained and replaced the instance. Correct for a compliance agent. Absurd for a metrics exporter. The September launch does not add a new capability; it undoes a coupling that should never have been the only option.
Anatomy: three parts, two guarantees, one switch
The pattern has three distinct resources. First, a daemon task definition — its own resource type with its own ARN (daemon-task-definition/...), separate from your application task definition. Second, a daemon, created with CreateDaemon, binding that definition to a cluster and to one or more ECS Managed Instances capacity providers. Third, the EC2 instances provisioned by those capacity providers, on each of which ECS keeps exactly one daemon task.
The first guarantee is ordering: ECS provisions the instance, starts the daemon task, and only then promotes the application task to RUNNING. Independent measurements published in April 2026 showed the daemon reaching RUNNING 18 to 21 seconds ahead of the application, with the instance held in REGISTERING during that window. That ordering applies to every daemon, critical or not. This is the point I most often see misread: marking a daemon non-critical does not cost you the guarantee that the agent comes up before traffic; it only costs you the guarantee that it stays up.
The second guarantee is remediation, and that is what the critical switch governs. Note how ECS remediates: it does not restart the container, it drains and replaces the whole instance. That is deliberately blunt — an agent that died may have left eBPF probes detached, network rules half-applied, buffers lost. Replacing the instance is the only cheap way back to a known state.
Instance lifecycle and the criticality branch
The startup ordering (left) is identical in both modes. The critical parameter only decides what happens after the daemon fails — and the non-critical branch is only safe if the observability arm is wired up.
- Managed Instances · capacity provider
- EC2 instance · state: REGISTERING
- Daemon task · exactly 1 per instance
- critical = true | false · per-daemon, default true
- Registration blocked · instance never goes ACTIVE
- DRAINING + replace · ~5 min per wave, 25% default
- Instance stays ACTIVE · running tasks untouched
- Placement continues · registration never blocked
- Coverage gap · silent unless observed
- EventBridge · Daemon service action
- Service action log · critical + non-critical
- CloudWatch alarm · + bake time rollback
- Coverage SLO · % instances with healthy daemon
What actually differs between the two modes
| Critical (default) | Non-critical (critical=false) | |
|---|---|---|
| Daemon fails to start | Instance never completes registration; no application task is placed on it | Registration is never blocked; application tasks launch immediately |
| Daemon stops or goes unhealthy later | ECS drains and replaces the whole instance (auto-repair) | Instance stays ACTIVE; existing tasks are untouched |
| Placement of new tasks | Stops on the affected instance | Continues normally, agent or no agent |
| Startup ordering | Daemon before the application | Daemon before the application — identical |
| Signal emitted on failure | EventBridge event + service action log | EventBridge event + service action log — identical |
| Residual risk you take on | Fleet churn: an unstable agent turns into cascading instance replacement | Blind spot: coverage degrades silently if nobody consumes the event |
When to use each mode: the rule I apply
The rule fits in one line: mark as critical the agent whose absence changes what the system is allowed to do; mark as non-critical the agent whose absence only changes what you can see. A runtime EDR, a network policy enforcer, an mTLS sidecar, or a file-integrity agent required by PCI DSS fall in the first group — without them the instance should not be eligible to process a transaction. An OTel metrics collector, a node exporter, a continuous profiler fall in the second.
The nuance lives in the log router. In financial environments the log often is the audit trail: "what you can see" becomes "what you can prove", and Fluent Bit stops being auxiliary. Do not classify by tool category; classify by the regulatory obligation that stream underwrites. If the agent's local buffer survives the outage window without dropping events, non-critical is defensible; if it drops them, it is critical.
The design corollary is what pays off most in practice: because criticality is per daemon, and a capacity provider accepts multiple daemons, do not package agents with different contracts into the same task definition. A task definition bundling the EDR and the metrics collector forces the stricter contract on both — and turns a collector memory leak into fleet replacement. Two daemons, two release cycles, two owners, two criticalities.
"Non-critical" is a control-plane term, not a business term. The parameter describes what ECS does to the instance — not how much that agent matters to you.
What you pay for classifying wrong — in both directions
Too critical. A bad agent revision makes the task flap, and every flap becomes an instance replacement. On a 60-instance fleet with the drain percentage at its default of 25%, that is 15 simultaneous replacements per wave; at the measured ~4m50s per wave, a one-line agent change costs roughly 20 minutes of fleet rotation. The direct bill impact is modest and computable: the Managed Instances management fee for a c6a.2xlarge is US$0.037/hour per instance (Oregon), so 60 instances add up to ~US$1,620/month in fee alone, plus EC2 and the overlap during draining. The expensive bill is elsewhere: application task rescheduling, drained connections, cold caches, cold JIT.
Two defaults conspire here. Bake time defaults to 0 minutes — meaning that once the last wave finishes, the window in which the circuit breaker watches alarms to roll back is nil. A regression that only shows up under load sails right through.
Too non-critical. Fail-open emits no pain: the instance stays ACTIVE, the application SLO does not move, and agent coverage decays in silence. Add the documented operational trap: daemon configuration settings are not persisted between updates, and critical defaults to true. An UpdateDaemon fired by a pipeline without an explicit --no-critical re-arms fleet-wide churn that nobody asked for. It is exactly the kind of change that only surfaces at the next incident.
Anti-patterns this launch makes easy
- Marking everything non-critical to "stop the churn" — you did not remove the failure, you just muted the alarm it used to pull.
- Flipping to non-critical without first wiring the EventBridge rule for daemon events to a destination that wakes somebody up. Fail-open with no event consumer is a compliance blind spot that looks like stability.
- Packaging the security agent and the telemetry agent in the same daemon task definition, forcing a single failure contract onto software with opposite risk profiles.
- Managing daemons via ad-hoc CLI calls: since
UpdateDaemondoes not persist settings andcriticalreverts to thetruedefault, every partial call is a silent contract change. - Keeping bake time at 0 while configuring alarms — paying the cognitive cost of the circuit breaker without buying the observation window that makes it useful.
- Treating the critical daemon as a substitute for application health checking. It repairs agent coverage, not business health; a healthy agent on a disk-full instance is still "healthy".
A Well-Architected reading of the decision
Security
Fail-closed remains the correct default for enforcement agents: a critical daemon keeps the instance from registering without coverage. Govern who may loosen it with IAM on ecs:CreateDaemon/ecs:UpdateDaemon, scoped by daemon ARN and conditioned on tags, so the security team owns the security daemon and the platform team owns the rest.
Reliability
Non-critical removes a real correlated failure mode: an agent regression hitting every instance at once used to produce simultaneous fleet replacement. In exchange, agent recovery stops being automatic — plan explicit repair.
Reference configuration I would take to production
Two daemons per capacity provider: sec-runtime with critical: true and obs-otel with critical: false. Drain percentage at 10 (not 25) so a bad wave hits 10% of the fleet, and bake time between 15 and 30 minutes with at least two CloudWatch alarms wired to the circuit breaker — one on application errors, one on the agent's own health. One EventBridge rule capturing daemon service action and daemon deployment state change events, targeting SNS for the critical daemon and a queue/Lambda feeding the coverage SLO for the non-critical one. Every daemon declared in full in IaC — never by partial CLI call — with drift detection, because UpdateDaemon reverts whatever you omit. And check the instance profile: it needs AmazonECSInstanceRolePolicyForManagedInstances; the legacy AmazonEC2ContainerServiceforEC2Role policy stops the daemon from starting.
I have watched a memory leak in an observability agent turn into node rotation during a settlement window, and the post-mortem did not name the leak as root cause — it named the fact that nobody had ever written down which agents were allowed to die. Since then I require an explicit criticality field in the ADR for any agent before it lands on the platform, with the owner and the regulatory obligation it underwrites next to it. This launch finally gives me a place in the control plane to materialize that decision instead of leaving it implicit in a runbook. What I would not do is use critical: false as a painkiller: if an agent fails often enough to hurt, the agent is the problem, and marking it non-critical merely trades a noisy incident for a silent gap. My default stays critical, and every exception needs a coverage SLO to get approved.
Verdict
Adopt it — and treat critical as an architectural decision, not a tuning flag. Keep the critical default for enforcement agents (EDR, network policy, mTLS, file integrity) and for log routers that underwrite an audit trail. Move to non-critical only metrics, profiling and telemetry whose temporary loss is not a loss of evidence — and only after the EventBridge rule has a consumer and the coverage SLO is published. Split agents with different contracts into different daemons, drop the drain percentage to 10, raise bake time to 15–30 minutes, and declare everything in IaC, because UpdateDaemon silently reverts omissions to critical: true. If your cluster is not on Managed Instances yet, this launch does not change your roadmap; if it is, it closes the last reasonable excuse for keeping an agent sidecar in every task definition.
References
Architecture, AWS, AI and market deep dives — straight to your inbox. Free.
No spam · unsubscribe anytime
Ask Fernando about this
Get a focused answer about this article from my AI assistant, grounded in my work.
Join the conversation
Sign in to comment
Verify your email to join in — you'll also get the newsletter. No password.
Keep reading
Architecture intelligence, in your inbox
Curated signals and original analysis on AWS, AI, distributed systems and the market — the way a solutions architect reads them.
- Curated AWS · AI · architecture · market signals
- New architecture studies & deep-dives when they ship
- Sharp summaries — depth without the noise
- No spam · double opt-in · unsubscribe anytime