# ECS Service Heatmap-Based Schedule Opportunity

> Usage heatmaps built from a service's CPU and memory reveal repeating idle windows (nights, weekends), and ZopNight converts the measured idle fraction directly into the saving: a service idle 60% of the week saves 60% of its compute. Applying the schedule sets desired count to 0 on that cron automatically.

Source: https://zop.dev/integrations/aws/recommendations/ecs-service-heatmap-based-schedule-opportunity
Updated: 2026-08-19

---

## From heatmap to cron

The aggregator builds each service a weekly activity heatmap from both [the CPU and memory series ECS emits](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/cloudwatch-metrics.html).
Two axes mean a memory-resident but CPU-quiet workload still reads as busy. When the map
shows a repeating idle window, it yields a concrete start/stop cron pair and a measured
idle percentage, and that percentage times the service's measured monthly cost is the
saving, because Fargate and EC2 capacity [is charged only while tasks run](https://aws.amazon.com/ecs/pricing/). Nothing is assumed about your working hours; a service idle Tuesday afternoons
saves Tuesday afternoons.

## Genuinely actionable, not advisory

ECS services are in ZopNight's schedulable set: applying this recommendation has the
executor drive the service's desired count to zero and back on the recommended cron. That
distinguishes it from schedule findings on resources with no native off switch: here the
lever is a supported operation, reversible by editing or deleting the schedule.

## The fences around it

Production services never fire. A prod-pattern name or environment tag vetoes before any
math, because a forced off-hours stop of production is an outage wearing a savings badge.
Services idle 95% of the week or more also abstain: that shape is not a schedule
candidate but a scale-to-zero candidate, owned by the running-idle rule, and emitting a
schedule there would claim near-total savings for keeping a nearly-dead service on a
timer. No heatmap, no cron pair, or no priced cost each abstain as well.

## Look at the shape yourself

```bash
aws cloudwatch get-metric-statistics \
  --namespace AWS/ECS --metric-name CPUUtilization \
  --dimensions Name=ClusterName,Value=my-cluster Name=ServiceName,Value=my-service \
  --start-time "$(date -u -v-14d +%Y-%m-%dT%H:%M:%SZ)" \
  --end-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  --period 3600 --statistics Average
```

Hourly resolution over two weeks shows the weekly rhythm the heatmap formalizes.

## What to verify before enabling

Scheduled scale-to-zero interacts with everything that assumes the service exists at
night: cron jobs that call it, monitors that alert on its absence, deploy pipelines that
roll at 2 a.m. Walk those first, then enable the schedule and let the first week run with
someone watching. Tasks stopped on schedule restart clean the next morning; the risk is
never the mechanism, it is the dependency nobody listed.
