perf(coordinator): parallelize RCI fetches with bounded, staged concurrency#39
Merged
cataseven merged 2 commits intocataseven:mainfrom Apr 13, 2026
Merged
perf(coordinator): parallelize RCI fetches with bounded, staged concurrency#39cataseven merged 2 commits intocataseven:mainfrom
cataseven merged 2 commits intocataseven:mainfrom
Conversation
…rrency # perf(coordinator): parallelize RCI fetches with bounded, staged concurrency ## Summary Replace the sequential fetch loop in `KeeneticCoordinator._async_update_data` with bounded, staged parallelism. This shortens each coordinator tick on mid-range Keenetic hardware and, on slower routers or busier networks, helps the coordinator stay within `FAST_SCAN_INTERVAL` instead of overrunning it (which causes Home Assistant to silently skip ticks and roughly double the observed update cadence). This is a self-contained change: only the body of `_async_update_data` is touched. No public API, no entity descriptions, no other files. ## What this PR does The fetches are split into three dependency stages, each internally parallel, with a shared `asyncio.Semaphore(4)` capping concurrent in-flight RCI calls: | Stage | Calls | Depends on | |---|---|---| | **1** | `system_info`, `current_version`, `available_version`, `interfaces`, `clients`, `mesh_nodes`, `client_stats`, `host_policies`, `ndns_info`, `usb_storage`, `interface_stats`, `ping_check_status` | — | | **2** | `wifi`, `wireguard`, `vpn_tunnels`, `wan_status`, `wan_interfaces`, `traffic_stats`, `port_info` | stage 1 (`interfaces`) | | **3** | `wifi_passwords` (per missing SSID), `mesh_usb` (per connected node) | stages 1–2 | Concurrency is bounded to 4 because Keenetic's RCI is a single HTTP surface served by a modest router CPU; firing 15+ requests fully in parallel risks 503s or auth contention on lower-end hardware. All `gather` calls use `return_exceptions=True`, and a small `_ok()` helper normalises any failed fetch into a safe default of the correct shape. As a side effect, a single flaky endpoint no longer kills the entire update tick — that data point is simply absent for one cycle and the next tick retries it. WAN enrichment, role labelling, throughput-delta calculation, the new-client detection, and the final return dict are byte-for-byte unchanged.
cataseven
approved these changes
Apr 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replace the sequential fetch loop in
KeeneticCoordinator._async_update_datawith bounded, staged parallelism. This shortens each coordinator tick on mid-range Keenetic hardware and, on slower routers or busier networks, helps the coordinator stay withinFAST_SCAN_INTERVALinstead of overrunning it (which causes Home Assistant to silently skip ticks and roughly double the observed update cadence).This is a self-contained change: only the body of
_async_update_datais touched. No public API, no entity descriptions, no other files.What this PR does
The fetches are split into three dependency stages, each internally parallel, with a shared
asyncio.Semaphore(4)capping concurrent in-flight RCI calls:system_info,current_version,available_version,interfaces,clients,mesh_nodes,client_stats,host_policies,ndns_info,usb_storage,interface_stats,ping_check_status