From 59a927ba93a457c45416b9b0d88c07e65cd29f3c Mon Sep 17 00:00:00 2001 From: Dragory <2606411+Dragory@users.noreply.github.com> Date: Sun, 12 Jan 2020 10:28:38 +0200 Subject: [PATCH] Update to Knub 28, improve debugger-friendliness Development npm scripts now also listen for debuggers: - Port 9229 for the bot - Port 9239 for the api Via Knub 28, PluginErrors are no longer used in development, which helps with call stacks in debuggers (see Knub changelog). Unhandled promise rejections are now treated as exceptions via nodejs flag --unhandled-rejections=strict, which allows catching them with a debugger. The internal "error-tolerant" error handler is now only used in production; in development, all unhandled errors cause the bot to crash and are easily catchable by debuggers. --- backend/package-lock.json | 6 +++--- backend/package.json | 10 ++++----- backend/src/index.ts | 45 ++++++++++++++++++++------------------- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index ff495015..fa229d2a 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -2776,9 +2776,9 @@ } }, "knub": { - "version": "27.0.0", - "resolved": "https://registry.npmjs.org/knub/-/knub-27.0.0.tgz", - "integrity": "sha512-iA332KoD2LN4R6c24HFGxQc8QH2GwG5Az97Rie5eqT5KFiWV/f5UJ8EfWhIJ/bOmMHubtJ4j+tEdQIBidC+WxA==", + "version": "28.0.0", + "resolved": "https://registry.npmjs.org/knub/-/knub-28.0.0.tgz", + "integrity": "sha512-dhLjlQP32AbkXoD0tUFrqa8/Emh/U5lvYXNCz+bIWiAlzYr1cQKRuh9qNjAL944sCWmtfhKXVMXRFS99P6M7qw==", "requires": { "escape-string-regexp": "^2.0.0", "knub-command-manager": "^7.0.0", diff --git a/backend/package.json b/backend/package.json index d8be4984..d110bee6 100644 --- a/backend/package.json +++ b/backend/package.json @@ -6,10 +6,10 @@ "scripts": { "watch": "cross-env NODE_ENV=development tsc-watch --onSuccess \"node start-dev.js\"", "build": "rimraf dist && tsc", - "start-bot-dev": "cross-env NODE_ENV=development node -r source-map-support/register -r ./register-tsconfig-paths.js dist/backend/src/index.js", - "start-bot-prod": "cross-env NODE_ENV=production node -r ./register-tsconfig-paths.js dist/backend/src/index.js", - "start-api-dev": "cross-env NODE_ENV=development node -r source-map-support/register -r ./register-tsconfig-paths.js dist/backend/src/api/index.js", - "start-api-prod": "cross-env NODE_ENV=production node -r ./register-tsconfig-paths.js dist/backend/src/api/index.js", + "start-bot-dev": "cross-env NODE_ENV=development node -r ./register-tsconfig-paths.js --unhandled-rejections=strict --inspect=127.0.0.1:9229 dist/backend/src/index.js", + "start-bot-prod": "cross-env NODE_ENV=production node -r ./register-tsconfig-paths.js --unhandled-rejections=strict dist/backend/src/index.js", + "start-api-dev": "cross-env NODE_ENV=development node -r ./register-tsconfig-paths.js --unhandled-rejections=strict --inspect=127.0.0.1:9239 dist/backend/src/api/index.js", + "start-api-prod": "cross-env NODE_ENV=production node -r ./register-tsconfig-paths.js --unhandled-rejections=strict dist/backend/src/api/index.js", "typeorm": "node -r ./register-tsconfig-paths.js ./node_modules/typeorm/cli.js", "migrate-prod": "npm run typeorm -- migration:run", "migrate-dev": "npm run build && npm run typeorm -- migration:run", @@ -32,7 +32,7 @@ "humanize-duration": "^3.15.0", "io-ts": "^2.0.0", "js-yaml": "^3.13.1", - "knub": "^27.0.0", + "knub": "^28.0.0", "knub-command-manager": "^7.0.0", "last-commit-log": "^2.1.0", "lodash.chunk": "^4.2.0", diff --git a/backend/src/index.ts b/backend/src/index.ts index 8490b3be..1128735d 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -24,33 +24,34 @@ const RECENT_DISCORD_ERROR_EXIT_THRESHOLD = 5; setInterval(() => (recentPluginErrors = Math.max(0, recentPluginErrors - 1)), 2500); setInterval(() => (recentDiscordErrors = Math.max(0, recentDiscordErrors - 1)), 2500); -function errorHandler(err) { - // tslint:disable:no-console - console.error(err); +if (process.env.NODE_ENV === "production") { + const errorHandler = err => { + // tslint:disable:no-console + console.error(err); - if (err instanceof PluginError) { - // Tolerate a few recent plugin errors before crashing - if (++recentPluginErrors >= RECENT_PLUGIN_ERROR_EXIT_THRESHOLD) { - console.error(`Exiting after ${RECENT_PLUGIN_ERROR_EXIT_THRESHOLD} plugin errors`); + if (err instanceof PluginError) { + // Tolerate a few recent plugin errors before crashing + if (++recentPluginErrors >= RECENT_PLUGIN_ERROR_EXIT_THRESHOLD) { + console.error(`Exiting after ${RECENT_PLUGIN_ERROR_EXIT_THRESHOLD} plugin errors`); + process.exit(1); + } + } else if (err instanceof DiscordRESTError || err instanceof DiscordHTTPError) { + // Discord API errors, usually safe to just log instead of crash + // We still bail if we get a ton of them in a short amount of time + if (++recentDiscordErrors >= RECENT_DISCORD_ERROR_EXIT_THRESHOLD) { + console.error(`Exiting after ${RECENT_DISCORD_ERROR_EXIT_THRESHOLD} API errors`); + process.exit(1); + } + } else { + // On other errors, crash immediately process.exit(1); } - } else if (err instanceof DiscordRESTError || err instanceof DiscordHTTPError) { - // Discord API errors, usually safe to just log instead of crash - // We still bail if we get a ton of them in a short amount of time - if (++recentDiscordErrors >= RECENT_DISCORD_ERROR_EXIT_THRESHOLD) { - console.error(`Exiting after ${RECENT_DISCORD_ERROR_EXIT_THRESHOLD} API errors`); - process.exit(1); - } - } else { - // On other errors, crash immediately - process.exit(1); - } - // tslint:enable:no-console + // tslint:enable:no-console + }; + + process.on("uncaughtException", errorHandler); } -process.on("unhandledRejection", errorHandler); -process.on("uncaughtException", errorHandler); - // Verify required Node.js version const REQUIRED_NODE_VERSION = "10.14.2"; const requiredParts = REQUIRED_NODE_VERSION.split(".").map(v => parseInt(v, 10));