Running ECS services behind a load balancer that served no requests and sat compute-idle for 30 days
What does ZopNight detect here?
ZopNight flags an ECS service with at least one running task when its load balancer target group's `RequestCountPerTarget` never read above 1 over 30 days and its tasks averaged no more than 5% CPU and 20% memory. The service pays full task compute for nothing, so the saving is its entire measured run-rate.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-044b |
| Category | idle |
| Severity | high |
| Metric | RequestCountPerTarget, CPUUtilization, MemoryUtilization |
| Threshold | RequestCountPerTarget at most 1 (average and peak); CPU avg 5% / peak 20%; memory avg 20% / peak 40% |
| Evaluation window | 30d |
| Source | ZopNight |
| Permissions used | ecs:ListServices · ecs:DescribeServices · elasticloadbalancing:DescribeTargetGroups · cloudwatch:GetMetricStatistics |
Where it applies
Running tasks bill for their CPU and memory, traffic or not
With AWS Fargate you pay for the vCPU, memory and storage your tasks consume while they run. On the EC2 launch type the tasks occupy container instances you pay for by the hour. Either way, a service with a desired count of two keeps two tasks alive around the clock, even if no request has reached it in weeks.
This is the running counterpart to ECS Idle Service, which covers services already scaled to zero.
Confirming a service gets no requests
Find the service’s target group, then look at RequestCountPerTarget. The
ALB metrics reference
says this metric takes the TargetGroup dimension on its own and is the target group’s requests
divided by its healthy targets:
aws ecs describe-services --cluster my-cluster --services my-service \ --query 'services[].[desiredCount,runningCount,loadBalancers[].targetGroupArn]'
aws cloudwatch get-metric-statistics \ --namespace AWS/ApplicationELB --metric-name RequestCountPerTarget \ --dimensions Name=TargetGroup,Value=targetgroup/my-tg/0123456789abcdef \ --start-time 2026-08-26T00:00:00Z --end-time 2026-09-25T00:00:00Z \ --period 86400 --statistics SumCheck the service’s CPUUtilization and MemoryUtilization in AWS/ECS as well.
No traffic and no background work
The service must have a desired count and a running count of at least 1. Its request series must cover 30 days and stay at or below 1 on both average and peak. Then comes the compute gate, which exists because plenty of services take no HTTP traffic yet do real work: queue consumers, workers, scheduled batch jobs. Over the same 30 days, CPU must average no more than 5% and peak no higher than 20%, and memory must average no more than 20% and peak no higher than 40%. Finally the service needs a priced cost.
Services this check cannot see
A worker with no load balancer has no request series, and a service behind a Network Load Balancer has no request count to read, so neither produces a finding. Missing CPU or memory data, less than 30 days of any series, or no price also means silence. The check never uses tags or names to decide a service is idle.
Saving the full run-rate
saving = measured monthly cost of the service's running taskscost after fix = 0 (scaled to zero or deleted)Scaling down a service nobody calls
- Confirm in the target group metrics that no client reaches it, and ask the owning team about internal or scheduled callers.
- Scale it to zero:
aws ecs update-service --cluster my-cluster --service my-service --desired-count 0. - If it is abandoned, delete it with
aws ecs delete-service --cluster my-cluster --service my-service --force. - Remove the listener rule and target group that pointed at it.