[amazonechocontrol] Poll notifications only while a channel is linked - #21442
Draft
ML19821 wants to merge 5 commits into
Draft
[amazonechocontrol] Poll notifications only while a channel is linked#21442ML19821 wants to merge 5 commits into
ML19821 wants to merge 5 commits into
Conversation
added 5 commits
August 18, 2026 10:44
Amazon reports the actual failure cause in the x-amzn-ErrorType header
(for /api/notifications: "ThrottlingException", body {"message":"Rate
exceeded"}, see openhab#19781), while the status line only carries a generic
"Bad Request". The header is now part of the exception message, and the
cookie-free response body is logged at DEBUG, capped at 512 characters
and only while TRACE is off - previously the body was only visible at
TRACE, which also dumps session cookies.
A response identified as throttled - status 429, or an x-amzn-ErrorType
starting with "ThrottlingException" - additionally fails fast instead of
going through the generic three retries with a fixed 2 s pause: those
all land inside the same limit window, and every retry is itself a
counted request that keeps the account throttled. FailMode.NORMAL keeps
its behaviour, it never retried in the first place.
The classification and the assembly of the failure reason are extracted
into two package-private static methods, so both can be tested without a
live response. The reason phrase is treated as optional, because a
response is not required to carry one.
Also adds the missing return after the "Request aborted." completion:
the second completeExceptionally() on a status of 0 was a no-op.
Related to openhab#19781, openhab#19714, openhab#21146.
AI-assisted-by: Claude Code
Signed-off-by: Martin Littkovsky <2018turtle@proton.me>
A failed notifications poll was indistinguishable from "no notifications set": getNotifications() swallowed the exception and returned an empty list, which set every next* channel to UNDEF (openhab#20018) and left nextRefreshNotifications at Long.MAX_VALUE, silently disabling the event-driven refresh until the next hourly cycle. The failure now propagates - getNotifications() is the only one of the swallowing list getters around it whose empty result is published as a statement about the device, the others feed command options and per-device states - and the caller distinguishes transient from sustained failure: the last known state survives short outages, and from the third consecutive failure onwards the next* channels go UNDEF, because at that point the binding genuinely does not know the state anymore. The update is repeated on every further failure, so an echo handler that registers during the outage is told as well. Retries back off from 300 s, doubling up to the regular 3600 s refresh interval and resetting on success; a flat retry interval measurably keeps a throttled account throttled. The third failure is therefore reached about 15 minutes after the first. refreshNotifications() also returns early while the backoff is running, so the push path (PUSH_NOTIFICATION_CHANGE) can no longer bypass it. Failure count, delay and the resulting deadline are one state and live together in NotificationPollBackoff behind one lock, because the poll is reached both from the polling job and from a Jetty I/O thread: with the deadline in a separate caller field, a poll succeeding on one thread and a poll failing on the other could each write one half and leave a backoff that never became due again. nextRefreshNotifications now carries only the success path's wake-up time. A re-login clears the backoff, so failures caused by the expired session do not keep the poll silent after the user has fixed it. Failures are logged once per streak at WARN, repeats at DEBUG, the transition to UNDEF at WARN and recovery at INFO. Related to openhab#20018, openhab#21146. AI-assisted-by: Claude Code Signed-off-by: Martin Littkovsky <2018turtle@proton.me>
Reduce the comments introduced by the two previous commits to short notes on actual constraints, as requested in review. No functional change; all changed lines are comments. Signed-off-by: Martin Littkovsky <2018turtle@proton.me> AI-assisted-by: Claude Code
Response bodies stay at TRACE; the DEBUG line keeps the metadata that matters, the x-amzn-ErrorType header and the status. AI-assisted-by: Claude Code Signed-off-by: Martin Littkovsky <2018turtle@proton.me>
The /api/notifications poll feeds nothing but the nextAlarm, nextTimer, nextReminder and nextMusicAlarm channels of the echo things. An account where none of them is linked pays requests to a hard-throttled endpoint for data without a consumer, so the link itself is the switch - no configuration flag. The gate sits in refreshNotifications(), covering the scheduled poll, the push refresh and the data refresh; a skip leaves the backoff untouched and logs one DEBUG line per suspension. Edge cases: the gate is re-evaluated on every attempt, so an echo handler registering after the account handler - the normal boot order - opens it on the next attempt. channelLinked() only arms the poll deadline: no I/O on the linking thread, and a burst of link events collapses into a single attempt that still runs through gate and backoff. A handler whose callback is already gone counts as unlinked instead of tripping the disposed-handler warning in isLinked(). The write direction (remind, playAlarmSound) is untouched. Signed-off-by: Martin Littkovsky <2018turtle@proton.me> AI-assisted-by: Claude Code
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.
Based on #21439; only the last commit is new; will be rebased and marked ready once it merges.
Problem
The account bridge polls
/api/notificationson a schedule and on everyPUSH_NOTIFICATION_CHANGE, but the result feeds only thenextAlarm,nextTimer,nextReminderandnextMusicAlarmchannels of the Echo things. An installation where none of them is linked pays requests to an endpoint Amazon throttles aggressively (see #20018, #21146) for data without a consumer.Changes
AccountHandler.refreshNotifications()skips the request while no Echo thing has one of these channels linked; all trigger paths run through it. The link itself is the switch — no configuration flag is added.EchoHandlerreports linked notification channels and overrideschannelLinked(): linking while suspended arms the poll deadline for the next scheduler tick — no I/O on the linking thread, a burst of link events (saving an.itemsfile) collapses into one attempt, and the woken poll still respects gate and backoff. The gate is re-evaluated on every attempt, so an Echo handler registering after the account handler (the normal boot order) opens it on the next attempt, and a disposed handler stops holding it open.Testing
AccountHandlerNotificationGateTest): gating per channel, push path, wake on link, link bursts, boot order, disposal window, backoff interaction. Full suite: 151 tests green.Transparency: this patch was developed with AI assistance (Claude); every commit carries an
AI-assisted-bytrailer. All changes were built, tested and verified on a production system by the author.