Skip to content

Commit

Permalink
fix(issues): Fix possible memory leak from event listeners
Browse files Browse the repository at this point in the history
  • Loading branch information
zachowj committed Aug 28, 2024
1 parent e4f057e commit 929a309
Showing 1 changed file with 32 additions and 8 deletions.
40 changes: 32 additions & 8 deletions src/common/services/IssueService/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,14 @@ const IssueTypeToRegistryEventMap = {
[IssueType.LabelId]: HaEvent.LabelRegistryUpdated,
} as const;

type IssueListener = (event?: HassStateChangedEvent) => void;

export interface Issue {
type: IssueType;
message: string;
identity: string;
hide?: boolean;
unsubscribe?: IssueListener;
}

interface FlowsStartedEvent {
Expand All @@ -102,7 +105,7 @@ interface FlowsStartedEvent {
};
}

const SIX_HOURS = 21600000;
const ONE_HOUR = 3600000;

export default class IssueService {
#nodesToCheck = new Map<string, BaseNodeProperties[]>();
Expand All @@ -118,7 +121,7 @@ export default class IssueService {
);

// every 6 hours, check all nodes for issues
setInterval(this.#handlePeriodicCheck.bind(this), SIX_HOURS);
setInterval(this.#handlePeriodicCheck.bind(this), ONE_HOUR);
}

#getChangedNodes(eventData: FlowsStartedEvent): NodeDef[] {
Expand Down Expand Up @@ -302,16 +305,16 @@ export default class IssueService {
case IssueType.StateId: {
// listen for state changes to check if the issue is fixed
const eventName = `ha_events:state_changed:${issue.identity}`;
const onEvent = (event: HassStateChangedEvent) => {
if (event.entity_id === issue.identity) {
const onEvent = (event?: HassStateChangedEvent) => {
if (event?.entity_id === issue.identity) {
const foundIssues = this.#checkForIssues(node);
// if the issue is still present, keep listening
if (!includesIssue(foundIssues, issue)) {
ha.eventBus.off(eventName, onEvent);
issue.unsubscribe?.();
}
}
};
ha.eventBus.on(eventName, onEvent);
this.#addListener(ha, issue, eventName, onEvent);
break;
}
case IssueType.AreaId:
Expand Down Expand Up @@ -340,10 +343,10 @@ export default class IssueService {
const foundIssues = this.#checkForIssues(node);
// if the issue is still present, keep listening
if (!includesIssue(foundIssues, issue)) {
ha.eventBus.off(event, onEvent);
issue.unsubscribe?.();
}
};
ha.eventBus.on(event, onEvent);
this.#addListener(ha, issue, event, onEvent);
}

#setIssue(nodeId: string, issues: Issue[]) {
Expand All @@ -357,6 +360,13 @@ export default class IssueService {
if (!this.#issues.has(nodeId)) {
return;
}

// remove listeners
const issues = this.#issues.get(nodeId);
issues?.forEach((issue) => {
issue.unsubscribe?.();
});

this.#issues.delete(nodeId);
this.#hiddenIssues.delete(nodeId);
RED.log.debug(`[Home Assistant] Issue removed: ${nodeId}`);
Expand Down Expand Up @@ -392,4 +402,18 @@ export default class IssueService {
#saveHiddenIssues() {
storageService.saveIssues(Array.from(this.#hiddenIssues));
}

#addListener(
ha: HomeAssistant,
issue: Issue,
event: string,
handler: IssueListener,
) {
ha.eventBus.on(event, handler);

issue.unsubscribe = () => {
ha.eventBus.removeListener(event, handler);
issue.unsubscribe = undefined;
};
}
}

0 comments on commit 929a309

Please sign in to comment.