Skip to content

perf: warm-boot fast path + atomic cloud request ids#29

Merged
foXaCe merged 3 commits into
mainfrom
perf/parallel-property-fetch
Jul 2, 2026
Merged

perf: warm-boot fast path + atomic cloud request ids#29
foXaCe merged 3 commits into
mainfrom
perf/parallel-property-fetch

Conversation

@foXaCe

@foXaCe foXaCe commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Résumé

Deux changements issus de l'investigation « temps de boot » :

fix : request ids cloud atomiques

send() lisait self._id hors verrou et l'incrémentait après l'appel : deux requêtes simultanées (thread MQTT, polling, commandes d'entités) pouvaient partir avec le même id, que le cloud Dreame rejette silencieusement (résultat vide, DEBUG only). Ids désormais alloués atomiquement, test de concurrence à l'appui (8 threads → 8 ids uniques).

perf : warm boot via inventaire de propriétés persisté

Le premier refresh bloquait sur 4 allers-retours robot séquentiels (~5-8 s selon la latence cloud ; plafond firmware : 50 clés/requête, lots de 87/100/200 rejetés — mesuré sur appareil). Le coordinator persiste maintenant l'inventaire des propriétés présentes (Store, clé model+firmware) :

  • boot chaud : seul le lot prioritaire (38 propriétés — tout ce que lit capability.load(), dont les flags à sémantique d'absence, + état principal) est chargé en bloquant ; le reste arrive d'un thread d'arrière-plan
  • les entités différées sont créées à l'identique (existence = inventaire) mais restent unavailable jusqu'à leur première valeur — chronologie inchangée
  • premier setup / changement de firmware : chargement complet inchangé, puis publication de l'inventaire

Mesuré (même fenêtre réseau) : setup entry 10,74 s → 5,84 s ; lot bloquant 8,4 s → 1,8-2,0 s.

Preuve « rien perdu » : diff du registre vide (258/258 entités, unique_id + disabled inclus) ; 0 entité rétrogradée de « valorisée » vers unavailable/unknown sur 146 états comparés avant/après ; 1 897 tests verts, mypy vert.

foXaCe added 3 commits July 2, 2026 12:34
Concurrent send() calls (MQTT thread + polling + entity commands) read
self._id outside the lock and incremented it after the call, so two
in-flight requests could share the same id and the cloud rejects the
duplicate with an empty result (silent, DEBUG-only).

Also documents why the first-refresh property fetch stays sequential
with 50-key batches: the robot rejects larger get_properties payloads
(100/200 fail) and answers the cloud bridge serially, so parallel
batches bring zero wall-clock gain (measured on device, 2026-07-02).
First refresh previously blocked on 4 serial robot round-trips
(~5-8 s depending on Dreame cloud latency). The coordinator now
persists the device's answered-property inventory (model/firmware
keyed, homeassistant.helpers.storage.Store). On warm boots only the
priority batch (every property DreameVacuumDeviceCapability.load()
reads — some flags are absence-based — plus the primary state) is
fetched synchronously; the remaining present properties load from a
background thread. Deferred entities are created identically
(existence = inventory) but stay unavailable until their first value
arrives, i.e. exactly the timeline they had before.

Cold boots (first setup, firmware change) keep the full synchronous
load and then publish the fresh inventory.

Measured on HA dev (same degraded-cloud window): cold 10.74 s ->
warm 5.84 s entry setup; priority batch 1.8-2.0 s vs 4.7-8.4 s full.
Proof of no loss: entity registry diff empty (258/258, unique_id and
disabled state included) and zero entities downgraded from valued to
unavailable/unknown across the change (146 recorder states compared).
@foXaCe foXaCe enabled auto-merge (squash) July 2, 2026 11:01
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6f2e0413-467b-4acd-b9bc-f8a1be4ed322

📥 Commits

Reviewing files that changed from the base of the PR and between ace22f6 and 820c9aa.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • custom_components/dreame_vacuum/coordinator.py
  • custom_components/dreame_vacuum/dreame/device.py
  • custom_components/dreame_vacuum/dreame/protocol.py
  • custom_components/dreame_vacuum/entity.py
  • tests/test_device_core.py
  • tests/test_protocol.py
  • tests/test_switch.py
  • tests/test_time.py
👮 Files not reviewed due to content moderation or server errors (9)
  • tests/test_protocol.py
  • custom_components/dreame_vacuum/dreame/protocol.py
  • tests/test_device_core.py
  • CHANGELOG.md
  • custom_components/dreame_vacuum/dreame/device.py
  • custom_components/dreame_vacuum/entity.py
  • tests/test_switch.py
  • custom_components/dreame_vacuum/coordinator.py
  • tests/test_time.py

📝 Walkthrough

[!WARNING]

Walkthrough skipped

File diffs could not be summarized.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/parallel-property-fetch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@foXaCe foXaCe merged commit b2d87a6 into main Jul 2, 2026
15 checks passed
@foXaCe foXaCe deleted the perf/parallel-property-fetch branch July 2, 2026 11:03
@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

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