Skip to content

Commit

Permalink
Add keepalive option in client.deactivate (#928)
Browse files Browse the repository at this point in the history
This change improves client cleanup when browsers close unexpectedly by adding
keepalive support to client deactivation. Previously, incomplete deactivation
left stale version vectors in the database, preventing proper garbage
collection.

---------

Co-authored-by: Youngteac Hong <[email protected]>
  • Loading branch information
JOOHOJANG and hackerwins authored Nov 20, 2024
1 parent d0ba8c3 commit 966ca89
Showing 1 changed file with 36 additions and 15 deletions.
51 changes: 36 additions & 15 deletions packages/sdk/src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ export class Client {
private setAuthToken: (token: string) => void;
private taskQueue: Array<() => Promise<any>>;
private processing = false;
private keepalive = false;

/**
* @param rpcAddr - the address of the RPC server.
Expand Down Expand Up @@ -235,6 +236,14 @@ export class Client {
createGrpcWebTransport({
baseUrl: rpcAddr,
interceptors: [authInterceptor, createMetricInterceptor()],
fetch: (input, init) => {
const newInit = {
...init,
keepalive: this.keepalive,
};

return fetch(input as RequestInfo, newInit);
},
}),
);
this.taskQueue = [];
Expand Down Expand Up @@ -278,28 +287,40 @@ export class Client {

/**
* `deactivate` deactivates this client.
*
* @param options - If keepalive is true, the client will request deactivation
* immediately using `fetch` with the `keepalive` option enabled. This is
* useful for ensuring the deactivation request completes even if the page is
* being unloaded, such as in `beforeunload` or `unload` event listeners.
*/
public deactivate(): Promise<void> {
public deactivate(options = { keepalive: false }): Promise<void> {
if (this.status === ClientStatus.Deactivated) {
return Promise.resolve();
}

return this.enqueueTask(async () => {
return this.rpcClient
.deactivateClient(
const task = async () => {
try {
await this.rpcClient.deactivateClient(
{ clientId: this.id! },
{ headers: { 'x-shard-key': this.apiKey } },
)
.then(() => {
this.deactivateInternal();
logger.info(`[DC] c"${this.getKey()}" deactivated`);
})
.catch(async (err) => {
logger.error(`[DC] c:"${this.getKey()}" err :`, err);
await this.handleConnectError(err);
throw err;
});
});
);
this.deactivateInternal();
logger.info(`[DC] c"${this.getKey()}" deactivated`);
} catch (err) {
logger.error(`[DC] c:"${this.getKey()}" err :`, err);
await this.handleConnectError(err);
throw err;
}
};

if (options.keepalive) {
this.keepalive = true;
const resp = task();
this.keepalive = false;
return resp;
}

return this.enqueueTask(task);
}

/**
Expand Down

0 comments on commit 966ca89

Please sign in to comment.