Skip to content

Commit 3e0d19b

Browse files
committed
feat(server): revoke displaced client during activation claim
1 parent 611fa3f commit 3e0d19b

3 files changed

Lines changed: 45 additions & 1 deletion

File tree

packages/server/src/__tests__/activation-commands.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,44 @@ describe("activation commands", () => {
232232
});
233233
});
234234

235+
it("claiming from a second client revokes the previous websocket", async () => {
236+
const request = createMockRequest();
237+
const revokeAndCloseClient = vi.fn();
238+
const ctx = createBaseContext({
239+
broadcaster: {
240+
broadcast: vi.fn(),
241+
sendToClient: vi.fn(() => true),
242+
sendBinaryToClient: vi.fn(() => true),
243+
getRequestMetadata: vi.fn(() => request),
244+
revokeAndCloseClient,
245+
} as unknown as Broadcaster,
246+
});
247+
248+
await dispatch(
249+
{
250+
kind: "command",
251+
id: "00000000-0000-4000-8000-000000000003",
252+
op: "activation.claim",
253+
args: { clientInstanceId: "client-a" },
254+
},
255+
ctx,
256+
"ws-a"
257+
);
258+
259+
await dispatch(
260+
{
261+
kind: "command",
262+
id: "00000000-0000-4000-8000-000000000004",
263+
op: "activation.claim",
264+
args: { clientInstanceId: "client-b" },
265+
},
266+
ctx,
267+
"ws-b"
268+
);
269+
270+
expect(revokeAndCloseClient).toHaveBeenCalledWith("ws-a", 2);
271+
});
272+
235273
it("does not block direct internal dispatches without websocket request metadata", async () => {
236274
const ctx = createBaseContext();
237275

packages/server/src/commands/activation.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ registerCommand(
2020
};
2121
}
2222

23-
return ctx.activationMgr.claim(args.clientInstanceId, clientId, request);
23+
const claim = ctx.activationMgr.claim(args.clientInstanceId, clientId, request);
24+
if (claim.displacedWsClientId) {
25+
ctx.broadcaster.revokeAndCloseClient?.(claim.displacedWsClientId, claim.generation);
26+
}
27+
28+
return claim;
2429
}
2530
);
2631

packages/server/src/ws/hub.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export interface Broadcaster {
6262
sendToClient(clientId: ClientId, msg: ServerToClient): boolean;
6363
sendBinaryToClient(clientId: ClientId, data: Buffer): boolean;
6464
getRequestMetadata?(clientId: ClientId): FastifyRequest | undefined;
65+
revokeAndCloseClient?(clientId: ClientId, generation: number): void;
6566
}
6667

6768
export class WsHub implements Broadcaster {

0 commit comments

Comments
 (0)