From dd8fb7cf6cd19c48ac7459fa31b0d23fd8cc2555 Mon Sep 17 00:00:00 2001 From: Timo Date: Tue, 15 Jul 2025 17:06:29 +0200 Subject: [PATCH 1/5] make delayed event restart `localTimeoutMs` configurable --- src/client.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/client.ts b/src/client.ts index 6ee06d4294..7950029cac 100644 --- a/src/client.ts +++ b/src/client.ts @@ -493,6 +493,12 @@ export interface IStartClientOpts { */ pollTimeout?: number; + /** + * The maximum amount of time to wait before timing out the `POST /_matrix/client/v1/delayed_events/{delay_id}` with `action = "restart"` requests. + * If not specified, the default `localTimeoutMs` will be used. + */ + delayedEventRestartLocalTimeoutMS?: number; + /** * The filter to apply to /sync calls. */ @@ -3473,8 +3479,12 @@ export class MatrixClient extends TypedEventEmitter Date: Tue, 15 Jul 2025 17:07:18 +0200 Subject: [PATCH 2/5] configure default to --- src/sync.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sync.ts b/src/sync.ts index 4509b69239..a617c90a9e 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -191,6 +191,7 @@ export function defaultClientOpts(opts?: IStoredClientOpts): IStoredClientOpts { initialSyncLimit: 8, resolveInvitesToProfiles: false, pollTimeout: 30 * 1000, + delayedEventRestartLocalTimeoutMS: 2300, pendingEventOrdering: PendingEventOrdering.Chronological, threadSupport: false, ...opts, From bcd651d75f0d8d7919ad0897443e69f55f2d93ca Mon Sep 17 00:00:00 2001 From: Timo Date: Wed, 16 Jul 2025 15:40:41 +0200 Subject: [PATCH 3/5] more context in comments --- src/client.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/client.ts b/src/client.ts index 7950029cac..2de56d4082 100644 --- a/src/client.ts +++ b/src/client.ts @@ -496,6 +496,13 @@ export interface IStartClientOpts { /** * The maximum amount of time to wait before timing out the `POST /_matrix/client/v1/delayed_events/{delay_id}` with `action = "restart"` requests. * If not specified, the default `localTimeoutMs` will be used. + * + * This setting is used in the context of MatrixRTC. We need to restart the dealyed events to make sure + * the HomeServer is sending the delayed rtc leave event. In bad network environments we might end up + * waiting for too long for the event to arrive and we will not send another restart event until the local timeout is reached. + * + * In those scenarios chances for success are higher if we use a lower local timeout to increase the tries we do instead of waiting + * for responses on requests which are stuck. */ delayedEventRestartLocalTimeoutMS?: number; From bab3d7122cbf00b65fe156e14c85e06c8e4022d4 Mon Sep 17 00:00:00 2001 From: Timo Date: Thu, 17 Jul 2025 15:59:57 +0200 Subject: [PATCH 4/5] move to create opts + test --- spec/unit/matrix-client.spec.ts | 26 ++++++++++++++++++++++++++ spec/unit/matrixrtc/mocks.ts | 2 ++ src/client.ts | 31 ++++++++++++++++--------------- src/sync.ts | 1 - 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/spec/unit/matrix-client.spec.ts b/spec/unit/matrix-client.spec.ts index f5299a3466..b1ea2a84f6 100644 --- a/spec/unit/matrix-client.spec.ts +++ b/spec/unit/matrix-client.spec.ts @@ -1082,6 +1082,32 @@ describe("MatrixClient", function () { await client._unstable_updateDelayedEvent(delayId, action); }); + + it("uses custom timeout for restart delayed event", async () => { + // make another client so we can pass creation opts + makeClient({ delayedEventRestartLocalTimeoutMS: 2300 }); + const delayId = "id"; + const action = UpdateDelayedEventAction.Restart; + httpLookups = [ + { + method: "POST", + prefix: unstableMSC4140Prefix, + path: `/delayed_events/${encodeURIComponent(delayId)}`, + data: { + action, + }, + }, + ]; + await client._unstable_updateDelayedEvent(delayId, action); + + expect(client.http.authedRequest).toHaveBeenLastCalledWith( + "POST", + "/delayed_events/id", + undefined, + { action: "restart" }, + { localTimeoutMs: 2300, prefix: "/_matrix/client/unstable/org.matrix.msc4140" }, + ); + }); }); describe("extended profiles", () => { diff --git a/spec/unit/matrixrtc/mocks.ts b/spec/unit/matrixrtc/mocks.ts index d61670d79f..a2b3e694e9 100644 --- a/spec/unit/matrixrtc/mocks.ts +++ b/spec/unit/matrixrtc/mocks.ts @@ -45,6 +45,7 @@ export const membershipTemplate: SessionMembershipData & { user_id: string } = { export type MockClient = Pick< MatrixClient, + | "http" | "getUserId" | "getDeviceId" | "sendEvent" @@ -65,6 +66,7 @@ export function makeMockClient(userId: string, deviceId: string): MockClient { cancelPendingEvent: jest.fn(), _unstable_updateDelayedEvent: jest.fn(), _unstable_sendDelayedStateEvent: jest.fn(), + http: { authedRequest: jest.fn() } as any, // Mocking http request for compatibility }; } diff --git a/src/client.ts b/src/client.ts index 2de56d4082..89b3807c91 100644 --- a/src/client.ts +++ b/src/client.ts @@ -340,6 +340,19 @@ export interface ICreateClientOpts { */ localTimeoutMs?: number; + /** + * The maximum amount of time to wait before timing out the `POST /_matrix/client/v1/delayed_events/{delay_id}` with `action = "restart"` requests. + * If not specified, it uses `localTimeoutMs` if set, otherwise there is no timeout. + * + * This setting is used in the context of MatrixRTC. We need to restart the dealyed events to make sure + * the HomeServer is sending the delayed rtc leave event. In bad network environments we might end up + * waiting for too long for the event to arrive and we will not send another restart event until the local timeout is reached. + * + * In those scenarios chances for success are higher if we use a lower local timeout to increase the tries we do instead of waiting + * for responses on requests which are stuck. + */ + delayedEventRestartLocalTimeoutMS?: number; + /** * Set to false to send the access token to the server via a query parameter rather * than the Authorization HTTP header. @@ -493,19 +506,6 @@ export interface IStartClientOpts { */ pollTimeout?: number; - /** - * The maximum amount of time to wait before timing out the `POST /_matrix/client/v1/delayed_events/{delay_id}` with `action = "restart"` requests. - * If not specified, the default `localTimeoutMs` will be used. - * - * This setting is used in the context of MatrixRTC. We need to restart the dealyed events to make sure - * the HomeServer is sending the delayed rtc leave event. In bad network environments we might end up - * waiting for too long for the event to arrive and we will not send another restart event until the local timeout is reached. - * - * In those scenarios chances for success are higher if we use a lower local timeout to increase the tries we do instead of waiting - * for responses on requests which are stuck. - */ - delayedEventRestartLocalTimeoutMS?: number; - /** * The filter to apply to /sync calls. */ @@ -1285,6 +1285,7 @@ export class MatrixClient extends TypedEventEmitter[0], { fetchFn: opts.fetchFn, baseUrl: opts.baseUrl, @@ -3487,7 +3488,7 @@ export class MatrixClient extends TypedEventEmitter Date: Thu, 17 Jul 2025 16:01:28 +0200 Subject: [PATCH 5/5] git commit --- spec/unit/matrixrtc/mocks.ts | 2 -- src/client.ts | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/unit/matrixrtc/mocks.ts b/spec/unit/matrixrtc/mocks.ts index a2b3e694e9..d61670d79f 100644 --- a/spec/unit/matrixrtc/mocks.ts +++ b/spec/unit/matrixrtc/mocks.ts @@ -45,7 +45,6 @@ export const membershipTemplate: SessionMembershipData & { user_id: string } = { export type MockClient = Pick< MatrixClient, - | "http" | "getUserId" | "getDeviceId" | "sendEvent" @@ -66,7 +65,6 @@ export function makeMockClient(userId: string, deviceId: string): MockClient { cancelPendingEvent: jest.fn(), _unstable_updateDelayedEvent: jest.fn(), _unstable_sendDelayedStateEvent: jest.fn(), - http: { authedRequest: jest.fn() } as any, // Mocking http request for compatibility }; } diff --git a/src/client.ts b/src/client.ts index 89b3807c91..72eec01b26 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1325,10 +1325,11 @@ export class MatrixClient extends TypedEventEmitter[0], { fetchFn: opts.fetchFn, baseUrl: opts.baseUrl,