Skip to content

Scaling

What’s built and verified here vs. the production plan for the parts that need real infra.

  • Downsampling (built): services/aggregation.downsample() rolls raw samples into hourly telemetry_aggregates (count + supply avg/min/max). Runs on the worker on a schedule; tested.
  • Retention (built): apply_retention(raw_max_age_days) drops raw rows past a cutoff once aggregated, so history survives compactly as aggregates; tested.
  • Partitioning (plan): in production, make telemetry a time-partitioned table — native Postgres declarative PARTITION BY RANGE (ts) with monthly partitions (via pg_partman), or a TimescaleDB hypertable. This keeps inserts and recent-range queries on small partitions and makes retention a cheap DROP PARTITION. Not applied to the dev table here (it would destabilize the test fixtures); it’s a forward migration at deploy time. The (device_id, ts) index already supports the access pattern.
  • Ingest buffer (plan, optional): for very large fleets, put a queue (Redis Streams / Kafka / managed) in front of the DB writer so spikes don’t backpressure devices; the store-and-forward buffer already lives on the agent, so brief backend unavailability never drops data.

The API is stateless (JWT, no server-side session), so it scales by adding replicas behind a load balancer — demonstrated in docs/loadtest-report.md (4 workers ≈ 4× a single worker, ~3,900 buildings within SLO on one host; add hosts for more). Caveats tracked in the security backlog: the rate limiter and Prometheus metrics are per-instance — move the limiter to a shared store and scrape each replica. Background work (downsample, retention, weather, alert eval) runs on a separate worker pool (arq/Celery + Redis) that scales independently.

Per-IP rate limiting sheds abuse; per-org plan entitlements cap fleet size commercially. For very large orgs, add per-device ingest rate caps and a 429 backoff the agent already honors (it buffers).

  • Ingest: p95 < 500 ms, error rate < 1% (load-test SLO, currently PASS).
  • Availability: target 99.9% on GET /health; the building’s heat is not affected by platform downtime (controllers run locally), so the error budget is about visibility/ops, not safety.
  • Burn-rate alerts on the error budget via the metrics in Phase 10.

Track DB storage growth (retention bounds it), egress, worker minutes, and SIM data (Integrations). Tie spend dashboards to the managed-platform billing API; alert on anomalies.

services/ota + api/ota_admin: publish a version, then a rollout reaches a deterministic stage_percent slice of the fleet (each device hashes to a stable 0–99 bucket). Advance 10 → 50 → 100 to expand the cohort monotonically; pause to halt. Devices pull their target from GET /ota/latest. Tested. Real signed/verified package serving + rollback on the device is Phase 4 (hardware).