# Running ECS Service Idle

> 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.

Source: https://zop.dev/integrations/aws/recommendations/running-ecs-service-idle
Updated: 2026-08-19

---

## 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](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-cloudwatch-metrics.html), 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](https://aws.amazon.com/ecs/pricing/), recoverable at
100% on scale-down, with an unpriced service abstaining rather than shipping a $0 card.

## Reproduce the traffic half

```bash
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 Maximum
```

## Acting 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.
