Fixes #17769, #22503: Improved subscription handling (#22889)

* Fixes #17769, #22503: Improved subscription handling

Prevent multiple active subscriptions
Ensure a clean state when the component reconnects
Checking subscription status before processing

* Prettier issue resolved

* async methods referencing _unsubscribe are properly awaited

* Apply suggestions from code review

Thank you

Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>

---------

Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>
This commit is contained in:
System Tester 2024-11-21 00:41:59 +10:00 committed by GitHub
parent 39b4e85dcd
commit b7f3e40340
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -138,7 +138,7 @@ export class HaLogbook extends LitElement {
this._throttleGetLogbookEntries.cancel(); this._throttleGetLogbookEntries.cancel();
this._updateTraceContexts.cancel(); this._updateTraceContexts.cancel();
this._updateUsers.cancel(); this._updateUsers.cancel();
this._unsubscribeSetLoading(); await this._unsubscribeSetLoading();
this._liveUpdatesEnabled = true; this._liveUpdatesEnabled = true;
@ -207,16 +207,26 @@ export class HaLogbook extends LitElement {
); );
} }
private _unsubscribe() { private async _unsubscribe(): Promise<void> {
if (this._subscribed) { if (this._subscribed) {
this._subscribed.then((unsub) => unsub?.()); try {
this._subscribed = undefined; const unsub = await this._subscribed;
if (unsub) {
await unsub();
this._subscribed = undefined;
this._pendingStreamMessages = [];
}
} catch (err: any) {
// eslint-disable-next-line
console.error("Error unsubscribing:", err);
}
} }
} }
public connectedCallback() { public connectedCallback() {
super.connectedCallback(); super.connectedCallback();
if (this.hasUpdated) { if (this.hasUpdated) {
// Ensure clean state before subscribing
this._subscribeLogbookPeriod(this._calculateLogbookPeriod()); this._subscribeLogbookPeriod(this._calculateLogbookPeriod());
} }
} }
@ -231,8 +241,8 @@ export class HaLogbook extends LitElement {
* Setting this._logbookEntries to undefined * Setting this._logbookEntries to undefined
* will put the page in a loading state. * will put the page in a loading state.
*/ */
private _unsubscribeSetLoading() { private async _unsubscribeSetLoading() {
this._unsubscribe(); await this._unsubscribe();
this._logbookEntries = undefined; this._logbookEntries = undefined;
this._pendingStreamMessages = []; this._pendingStreamMessages = [];
} }
@ -241,8 +251,8 @@ export class HaLogbook extends LitElement {
* Setting this._logbookEntries to an empty * Setting this._logbookEntries to an empty
* list will show a no results message. * list will show a no results message.
*/ */
private _unsubscribeNoResults() { private async _unsubscribeNoResults() {
this._unsubscribe(); await this._unsubscribe();
this._logbookEntries = []; this._logbookEntries = [];
this._pendingStreamMessages = []; this._pendingStreamMessages = [];
} }
@ -273,10 +283,12 @@ export class HaLogbook extends LitElement {
throw new Error("Unexpected time specified"); throw new Error("Unexpected time specified");
} }
private _subscribeLogbookPeriod(logbookPeriod: LogbookTimePeriod) { private async _subscribeLogbookPeriod(logbookPeriod: LogbookTimePeriod) {
if (this._subscribed) { if (this._subscribed) {
return true; return true;
} }
// Ensure any previous subscription is cleaned up
await this._unsubscribe();
this._subscribed = subscribeLogbook( this._subscribed = subscribeLogbook(
this.hass, this.hass,
(streamMessage) => { (streamMessage) => {
@ -304,7 +316,7 @@ export class HaLogbook extends LitElement {
this._error = undefined; this._error = undefined;
if (this._filterAlwaysEmptyResults) { if (this._filterAlwaysEmptyResults) {
this._unsubscribeNoResults(); await this._unsubscribeNoResults();
return; return;
} }
@ -312,7 +324,7 @@ export class HaLogbook extends LitElement {
if (logbookPeriod.startTime > logbookPeriod.now) { if (logbookPeriod.startTime > logbookPeriod.now) {
// Time Travel not yet invented // Time Travel not yet invented
this._unsubscribeNoResults(); await this._unsubscribeNoResults();
return; return;
} }