ECS services running tasks that serve no requests and do no work
What does ZopNight detect here?
Running tasks with zero traffic pay full Fargate or EC2 rates for nothing, so ZopNight demands a month of evidence on 3 fronts before saying so: load-balancer requests at or under 1 per period, CPU averaging 5% or less, and memory quiet. Zero HTTP alone does not prove a worker is idle.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-044b |
| Category | idle |
| Severity | high |
| Metric | none — pure configuration read |
| Source | ecs_running_idle.go |
Where it applies
Zero requests is not zero work
The trap in “idle service” detection is the worker: a queue consumer or scheduled batch service serves no HTTP ever, yet does real work in bursts. Scale one of those to zero on the strength of an empty request counter and you have broken a pipeline, not saved money. This rule therefore stacks a compute gate on top of the traffic gate. CPU must average at or under 5% and never peak past 20%, memory at or under 20% average and 40% peak, all with a full 30 days of coverage, so a service pinned at 100% CPU every midnight batch abstains no matter how empty its target group is.
The traffic signal and who it excludes
Request volume comes from the service’s ALB target group (the per-target request metric, which is queryable by target group alone), with both the window peak and mean required at or below a floor of 1 to tolerate stray health checks. The corollary is honest scope: services with no ALB (workers, NLB-fronted services) produce no such series, and the rule abstains on them entirely rather than guessing. Absent series, absent finding.
Scope boundaries with the neighbouring rules
Only genuinely running services qualify: desired and running counts both at least 1, read from discovery, with absent counts abstaining. Services already scaled to zero belong to the cleanup rule for parked service definitions; draining and failing services are excluded too. And the saving is the service’s full measured monthly compute run-rate, recoverable at 100% on scale-down, with an unpriced service abstaining rather than shipping a $0 card.
Reproduce the traffic half
aws cloudwatch get-metric-statistics \ --namespace AWS/ApplicationELB --metric-name RequestCountPerTarget \ --dimensions Name=TargetGroup,Value=targetgroup/my-tg/0123456789abcdef \ --start-time "$(date -u -v-30d +%Y-%m-%dT%H:%M:%SZ)" \ --end-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ --period 86400 --statistics Sum MaximumActing on a finding
Check the deployment history and any external scaler first: a service someone parks and wakes deliberately looks identical from the metrics. Then scale desired count to zero rather than deleting, watch for a week, and only then remove the service plus its target group and listener rule. The two-step version costs nothing extra and converts an irreversible call into a reversible one.