Skip to content

feat(gateway_sessions): prioritize user commands over status polls in command queue (#680) - #685

Merged
GreenGrassBlueOcean merged 4 commits into
OpenWebNet-HA:v2-phase1-architecturefrom
GreenGrassBlueOcean:feat/issue-680-command-priority
Oct 10, 2026
Merged

GreenGrassBlueOcean merged 4 commits into
OpenWebNet-HA:v2-phase1-architecturefrom
GreenGrassBlueOcean:feat/issue-680-command-priority

Conversation

@GreenGrassBlueOcean

Copy link
Copy Markdown
Contributor

What is the problem

User commands and background status requests previously shared a single FIFO asyncio.Queue in CommandWorkerPool.send_buffer (custom_components/myhome/gateway_sessions.py).

On busy installations, during reconnect discovery sweeps, or when the gateway experiences slow NACKs on unresponsive zones (#675), user-initiated actions (e.g. toggling a light, adjusting a shutter, changing climate setpoints) were queued behind dozens of telemetry and status polls. Even though is_status_request was already tracked on command envelopes, the queue made no priority distinction, causing noticeable real-world latency for interactive user commands.

Closes #680.


How it is solved

  1. Multi-Tier Priority Storage (_PriorityQueueStorage):

    • Implemented a specialized storage container backing CommandPriorityQueue, decomposing queued items into three priority tiers:
      • Tier 0 (_commands): High-priority user state mutations (is_status_request=False).
      • Tier 1 (_status): Lower-priority background telemetry and status polling (is_status_request=True).
      • Tier 2 (_others): Worker shutdown sentinels (None and custom termination tokens).
    • Strict FIFO ordering is preserved within each tier.
    • Dequeues from higher-priority tiers first: commands drain completely before status polls are emitted, and status polls drain before shutdown sentinels.
    • Full sequence and deque interface compatibility: implements __len__, __bool__, __iter__, __reversed__, __getitem__, __contains__, __eq__, append, appendleft, popleft, pop, remove, clear, copy, count, and index. This preserves 100% backward compatibility for tests directly inspecting list(handler.send_buffer._queue).
  2. Prioritized Backpressure & Deadlock-Free Cancellation (CommandPriorityQueue):

    • Subclasses asyncio.Queue[Any].
    • When the queue reaches maxsize, waiting command putters take precedence over waiting status poll putters via head-of-line insertion in self._putters.
    • Properly catches BaseException during await putter (in Python 3.8+, asyncio.CancelledError inherits from BaseException, not Exception), cleanly removing cancelled putters from self._putters and preventing orphaned waiter futures.
    • If a woken putter is cancelled after being granted a slot, self._wakeup_next(self._putters) is immediately invoked, preventing downstream waiters from starving or deadlocking.
  3. Invariants Preserved:

    • "Read-back after write" sequencing: When an entity mutation queues a write command immediately followed by a read-back status poll, the status poll is queued after the command and executes after it, ensuring correct state synchronization.
    • Shutdown drain semantics: Sentinels dequeue last, guaranteeing that pending commands and status queries drain cleanly before worker exit (preserving #302).
    • Zero single-session regression: Pacing and queue semantics on single-session gateways (MH200/MH201) and multi-session gateways (F454/MyHomeServer1) operate transparently.

How it is tested

  1. Dedicated Unit Tests (tests/test_gateway_sessions.py):

    • test_command_priority_queue_ordering: Verifies user commands dequeue ahead of queued status requests while preserving FIFO within each class.
    • test_command_priority_queue_read_back_after_write: Confirms write commands execute before their subsequent status read-back.
    • test_command_priority_queue_sentinels: Confirms None and custom sentinels dequeue strictly after all commands and status polls.
    • test_command_priority_queue_full_backpressure: Confirms waiting command putters take precedence when capacity frees up.
    • test_command_priority_queue_backpressure_cancellation: Proves cancelled waiting putters are cleanly removed from _putters.
    • test_command_priority_queue_woken_putter_cancellation_unblocks_next: Proves a woken putter cancelled during wake does not deadlock the queue.
    • test_command_priority_queue_storage_methods: Thorough verification of deque and sequence protocols.
    • test_worker_sends_user_command_ahead_of_pending_status_polls: End-to-end sending_loop test proving user commands are dispatched first to the mock gateway session.
  2. Test Suite & Verification Results:

    • tests/test_gateway_sessions.py: 19 passed in 1.73s.
    • Regression suite (test_gateway_sessions, test_blank_start, test_command_session_contract, test_issue_302, test_poll_health): 65 passed in 17.28s.
    • Full test suite: 3,632 passed in 331s (97.3% coverage on gateway_sessions.py).
    • Ruff static analysis: 0 violations across custom_components, tests, scripts.
    • Architectural validator (scripts/verify_ha_standards.py): All 54 rules satisfied.
    • Anti-drift sentinel (scripts/sync_documentation.py --check): All documentation and references verified in sync.

@GreenGrassBlueOcean
GreenGrassBlueOcean force-pushed the feat/issue-680-command-priority branch from 569e64d to 44e04b1 Compare October 10, 2026 09:24
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@GreenGrassBlueOcean
GreenGrassBlueOcean merged commit ac602b4 into OpenWebNet-HA:v2-phase1-architecture Oct 10, 2026
16 checks passed
@GreenGrassBlueOcean
GreenGrassBlueOcean deleted the feat/issue-680-command-priority branch October 10, 2026 11:14
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.

2 participants