Skip to content

Fix: getGlobalSettings accumulates orphaned listeners under concurrent or interleaved calls#139

Open
popcornhax wants to merge 2 commits intoelgatosf:mainfrom
popcornhax:main
Open

Fix: getGlobalSettings accumulates orphaned listeners under concurrent or interleaved calls#139
popcornhax wants to merge 2 commits intoelgatosf:mainfrom
popcornhax:main

Conversation

@popcornhax
Copy link
Copy Markdown

getGlobalSettings() currently uses connection.once() with no id filtering and no timeout. If a didReceiveGlobalSettings event arrives from an unrelated trigger (e.g., the property inspector) while a getGlobalSettings() promise is pending, the wrong event resolves the promise and the listener registered for the actual response is permanently orphaned. Under repeated calls this silently accumulates listeners.

This PR aligns getGlobalSettings() with the pattern already used by Action#fetch(): match by request id, use connection.disposableOn() for safe cleanup, and add a timeout to prevent indefinite awaiting. The DidReceiveGlobalSettings type already carries an optional id field for this purpose.

…interleaved calls

getGlobalSettings() currently uses connection.once() with no id filtering and no timeout. If a didReceiveGlobalSettings event arrives from an unrelated trigger (e.g., the property inspector) while a getGlobalSettings() promise is pending, the wrong event resolves the promise and the listener registered for the actual response is permanently orphaned. Under repeated calls this silently accumulates listeners.

This PR aligns getGlobalSettings() with the pattern already used by Action#fetch(): match by request id, use connection.disposableOn() for safe cleanup, and add a timeout to prevent indefinite awaiting. The DidReceiveGlobalSettings type already carries an optional id field for this purpose.
Fixed import, timeout and formatting.
Copy link
Copy Markdown
Member

@GeekyEggo GeekyEggo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR; overall the changes look good, just one minor change request.

}, REQUEST_TIMEOUT);

const listener = connection.disposableOn("didReceiveGlobalSettings", (ev: DidReceiveGlobalSettings<T>): void => {
if (ev.id === id) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This id check can be removed; with global settings being shared, it's safe to assume that any didReceiveGlobalSettings event can fulfil any-and-all pending promises.

For request completeness, the id should still be sent with the request, but needn't be checked when receiving the global settings, e.g. the following is fine:

connection.send({
		event: "getGlobalSettings",
		context: connection.registrationParameters.pluginUUID,
		id: randomUUID(),
});

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