Skip to content

Commit

Permalink
make Deno capture unhandled exceptions and rejections and report them…
Browse files Browse the repository at this point in the history
  • Loading branch information
d-gubert committed Dec 6, 2024
1 parent 09e1141 commit 812a6ed
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 0 deletions.
33 changes: 33 additions & 0 deletions deno-runtime/error-handlers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as Messenger from './lib/messenger.ts';

export function unhandledRejectionListener(event: PromiseRejectionEvent) {
event.preventDefault();

const { type, reason } = event;

Messenger.sendNotification({
method: 'unhandledRejection',
params: [
{
type,
reason: reason instanceof Error ? reason.message : reason,
timestamp: new Date(),
},
],
});
}

export function unhandledExceptionListener(event: ErrorEvent) {
event.preventDefault();

const { type, message, filename, lineno, colno } = event;
Messenger.sendNotification({
method: 'uncaughtException',
params: [{ type, message, filename, lineno, colno }],
});
}

export default function registerErrorListeners() {
addEventListener('unhandledrejection', unhandledRejectionListener);
addEventListener('error', unhandledExceptionListener);
}
3 changes: 3 additions & 0 deletions deno-runtime/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import videoConferenceHandler from './handlers/videoconference-handler.ts';
import apiHandler from './handlers/api-handler.ts';
import handleApp from './handlers/app/handler.ts';
import handleScheduler from './handlers/scheduler-handler.ts';
import registerErrorListeners from './error-handlers.ts';

type Handlers = {
app: typeof handleApp;
Expand Down Expand Up @@ -126,4 +127,6 @@ async function main() {
}
}

registerErrorListeners();

main();
2 changes: 2 additions & 0 deletions src/definition/metadata/AppMethod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,6 @@ export enum AppMethod {
EXECUTE_POST_USER_STATUS_CHANGED = 'executePostUserStatusChanged',
// Runtime specific methods
RUNTIME_RESTART = 'runtime:restart',
RUNTIME_UNCAUGHT_EXCEPTION = 'runtime:uncaughtException',
RUNTIME_UNHANDLED_REJECTION = 'runtime:unhandledRejection',
}
18 changes: 18 additions & 0 deletions src/server/runtime/deno/AppsEngineDenoRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { IParseAppPackageResult } from '../../compiler';
import { AppConsole, type ILoggerStorageEntry } from '../../logging';
import type { AppAccessorManager, AppApiManager } from '../../managers';
import { AppStatus } from '../../../definition/AppStatus';
import type { AppMethod } from '../../../definition/metadata';
import { bundleLegacyApp } from './bundler';
import { ProcessMessenger } from './ProcessMessenger';
import { LivenessManager } from './LivenessManager';
Expand Down Expand Up @@ -535,12 +536,29 @@ export class DenoRuntimeSubprocessController extends EventEmitter {
case 'log':
console.log('SUBPROCESS LOG', message);
break;
case 'unhandledRejection':
case 'uncaughtException':
await this.logUnhandledError(`runtime:${method}`, message);
break;

default:
console.warn('Unrecognized method from sub process');
break;
}
}

private async logUnhandledError(
method: `${AppMethod.RUNTIME_UNCAUGHT_EXCEPTION | AppMethod.RUNTIME_UNHANDLED_REJECTION}`,
message: jsonrpc.IParsedObjectRequest | jsonrpc.IParsedObjectNotification,
) {
this.debug('Unhandled error of type "%s" caught in subprocess', method);

const logger = new AppConsole(method);
logger.error(message.payload);

await this.logStorage.storeEntries(AppConsole.toStorageEntry(this.getAppId(), logger));
}

private async handleResultMessage(message: jsonrpc.IParsedObjectError | jsonrpc.IParsedObjectSuccess): Promise<void> {
const { id } = message.payload;

Expand Down

0 comments on commit 812a6ed

Please sign in to comment.