Skip to content

Speed up coordinator refresh with parallel fetches and landscape lock#401

Merged
sebr merged 1 commit intomainfrom
faster-coordinator-refresh
Apr 20, 2026
Merged

Speed up coordinator refresh with parallel fetches and landscape lock#401
sebr merged 1 commit intomainfrom
faster-coordinator-refresh

Conversation

@sebr
Copy link
Copy Markdown
Owner

@sebr sebr commented Apr 20, 2026

Summary

Periodic coordinator refreshes were logging ~2s durations. Investigation
showed two causes that are independent of the B-hyve API's own latency:

  1. Sequential top-level fetches. devices and timer_programs are
    independent endpoints but were awaited one after the other, and the
    per-device history/landscape loop iterated devices serially.
  2. Duplicate landscape requests. The coordinator fans out
    get_landscape(device_id, zone_id) per zone in parallel. Each call
    routes through client._refresh_landscapes(device_id), which had no
    single-flight guard — so on a cold cache (every periodic refresh,
    since API_POLL_PERIOD equals the 5-min coordinator interval) all
    N zones raced and fired N identical HTTP requests to the same
    /landscape_descriptions/{device_id} endpoint.

Changes:

  • coordinator._async_update_data now gathers devices and
    timer_programs concurrently, and fans out per-device history +
    landscape bundles across all devices in parallel via a new
    _fetch_device_bundle helper.
  • client._refresh_landscapes now holds a per-device asyncio.Lock.
    Concurrent callers for the same device share one HTTP request; the
    followers see the fresh timestamp on re-entry and return from cache.

Expected impact: a single-device account should see refresh time drop
from roughly 3 serial roundtrips to roughly 1 (bounded by the slowest
single roundtrip), plus the elimination of N-1 duplicate landscape
requests per zone. Multi-device accounts benefit further from the
cross-device parallelism.

Test plan

  • ./scripts/test — 153 passed, 5 skipped
  • ./scripts/lint — all checks passed
  • Added regression test test_concurrent_calls_dedupe_to_single_request
    in tests/test_client.py that proves concurrent get_landscape
    calls for the same device now fire a single HTTP request

Periodic refreshes were taking ~2s because independent endpoints were
awaited sequentially and parallel per-zone landscape lookups each fired
a duplicate HTTP request to the same device-level endpoint.

- Gather `devices` and `timer_programs` concurrently in the coordinator
- Fan out per-device history/landscape bundles across all devices in
  parallel (previously the outer device loop was sequential)
- Add a per-device `asyncio.Lock` around `_refresh_landscapes` so
  concurrent callers share one HTTP request instead of duplicating N
@sebr sebr merged commit 86dadd4 into main Apr 20, 2026
4 checks passed
@sebr sebr deleted the faster-coordinator-refresh branch April 20, 2026 01:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant