mirror of
https://github.com/RocketChat/Rocket.Chat.git
synced 2025-12-28 06:47:25 +00:00
fix: unhandled rejection from stale runtime (#36670)
This commit is contained in:
parent
c48070da8d
commit
42979690f3
6
.changeset/twelve-plums-turn.md
Normal file
6
.changeset/twelve-plums-turn.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
'@rocket.chat/meteor': patch
|
||||
'@rocket.chat/apps-engine': patch
|
||||
---
|
||||
|
||||
Fixes an issue that would cause the chat server to crash with an unhandled rejection in some cases
|
||||
@ -85,6 +85,8 @@ export type DenoRuntimeOptions = {
|
||||
timeout: number;
|
||||
};
|
||||
|
||||
type AbortFunction = (reason?: any) => void;
|
||||
|
||||
export class DenoRuntimeSubprocessController extends EventEmitter {
|
||||
private deno: child_process.ChildProcess | undefined;
|
||||
|
||||
@ -322,13 +324,17 @@ export class DenoRuntimeSubprocessController extends EventEmitter {
|
||||
|
||||
const request = jsonrpc.request(id, message.method, message.params);
|
||||
|
||||
const promise = this.waitForResponse(request, options).finally(() => {
|
||||
const { promise, abort } = this.waitForResponse(request, options);
|
||||
|
||||
try {
|
||||
this.messenger.send(request);
|
||||
} catch (e) {
|
||||
abort(e);
|
||||
}
|
||||
|
||||
return promise.finally(() => {
|
||||
this.debug('Request %s for method %s took %dms', id, message.method, Date.now() - start);
|
||||
});
|
||||
|
||||
this.messenger.send(request);
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
private waitUntilReady(): Promise<void> {
|
||||
@ -353,27 +359,41 @@ export class DenoRuntimeSubprocessController extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
private waitForResponse(req: jsonrpc.RequestObject, options = this.options): Promise<unknown> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const responseCallback = (result: unknown, error: jsonrpc.IParsedObjectError['payload']['error']) => {
|
||||
clearTimeout(timeoutId);
|
||||
private waitForResponse(req: jsonrpc.RequestObject, options = this.options): { abort: AbortFunction; promise: Promise<unknown> } {
|
||||
const controller = new AbortController();
|
||||
const { abort, signal } = controller;
|
||||
|
||||
if (error) {
|
||||
reject(error);
|
||||
}
|
||||
return {
|
||||
abort: abort.bind(controller),
|
||||
promise: new Promise((resolve, reject) => {
|
||||
const eventName = `result:${req.id}`;
|
||||
|
||||
resolve(result);
|
||||
};
|
||||
const responseCallback = (result: unknown, error: jsonrpc.IParsedObjectError['payload']['error'] | Error) => {
|
||||
this.off(eventName, responseCallback);
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
const eventName = `result:${req.id}`;
|
||||
if (error) {
|
||||
reject(error);
|
||||
}
|
||||
|
||||
const timeoutId = setTimeout(() => {
|
||||
this.off(eventName, responseCallback);
|
||||
reject(new Error(`[${this.getAppId()}] Request "${req.id}" for method "${req.method}" timed out`));
|
||||
}, options.timeout);
|
||||
resolve(result);
|
||||
};
|
||||
|
||||
this.once(eventName, responseCallback);
|
||||
});
|
||||
const timeoutId = setTimeout(
|
||||
() =>
|
||||
responseCallback(
|
||||
undefined,
|
||||
new Error(`[${this.getAppId()}] Request "${req.id}" for method "${req.method}" timed out after ${options.timeout}ms`),
|
||||
),
|
||||
options.timeout,
|
||||
);
|
||||
|
||||
signal.onabort = () =>
|
||||
responseCallback(undefined, signal.reason instanceof Error ? signal.reason : new Error(String(signal.reason)));
|
||||
|
||||
this.once(eventName, responseCallback);
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
private onReady(): void {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user