From 2608e08c9ef9997f216caa83f1abd6adacebb24b Mon Sep 17 00:00:00 2001 From: Alexis Tyler Date: Fri, 25 Sep 2020 15:24:34 +0930 Subject: [PATCH] fix(sentry): ensure we flush error queue before exiting --- app/index.ts | 35 +++++++++++++++++++++++++++------- app/server.ts | 13 ++++++++++--- ecosystem.config.js | 25 ++++++++++++------------ index.js | 46 +++++++-------------------------------------- 4 files changed, 57 insertions(+), 62 deletions(-) diff --git a/app/index.ts b/app/index.ts index 46664f5dd..8f26d3d15 100644 --- a/app/index.ts +++ b/app/index.ts @@ -3,10 +3,22 @@ * Written by: Alexis Tyler */ +import os from 'os'; import am from 'am'; +import * as Sentry from '@sentry/node'; import { core, loadServer } from '@unraid/core'; import { server } from './server'; +// Send errors to server if enabled +Sentry.init({ + dsn: process.env.SENTRY_DSN, + tracesSampleRate: 1.0, + release: require('../package.json').version, + environment: process.env.NODE_ENV, + serverName: os.hostname(), + enabled: Boolean(process.env.SENTRY_DSN) +}); + // Boot app am(async () => { // Load core @@ -14,13 +26,22 @@ am(async () => { // Load server await loadServer('graphql-api', server); -}, (error: NodeJS.ErrnoException) => { - // We should only end here if core has an issue loading +}, async (error: NodeJS.ErrnoException) => { + // Send error to server for debugging + Sentry.captureException(error); - // Log last error - console.error(error.message); + // Stop server + server.stop(async () => { + /** + * Flush messages to server before stopping. + * + * This may mean waiting up to 5s + * before the server actually stops. + */ + await Sentry.flush(5000); - // Kill application - // eslint-disable-next-line unicorn/no-process-exit - process.exit(1); + // Kill application + // eslint-disable-next-line unicorn/no-process-exit + process.exit(1); + }); }); diff --git a/app/server.ts b/app/server.ts index d485e0da4..36a24138d 100644 --- a/app/server.ts +++ b/app/server.ts @@ -190,7 +190,7 @@ export const server = { }); }); }, - stop() { + stop(callback?: () => void) { // Stop http server from accepting new connections and close existing connections stoppableServer.stop(globalErrorHandler); @@ -202,10 +202,17 @@ export const server = { // Unlink socket file if (isNaN(parseInt(port, 10))) { - fs.unlinkSync(port); + try { + fs.unlinkSync(port); + } catch {} } - log.info(`Successfully stopped ${serverName}`); + // Run callback + if (callback) { + return callback(); + } + + log.debug(`Successfully stopped ${serverName}`); // Gracefully exit exitApp(); diff --git a/ecosystem.config.js b/ecosystem.config.js index c09fe2bd8..95e3d0856 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -1,17 +1,6 @@ /* eslint-disable camelcase */ const path = require('path'); -const common = { - name: 'graphql-api', - script: path.resolve(__dirname, './dist/index.js'), - watch: false, - wait_ready: true, - listen_timeout: 3000, - exp_backoff_restart_delay: 100, - max_memory_restart: '200M', - PROCESS_TITLE: 'graphql-api' -}; - const envs = { env_development: { PORT: 5000, @@ -19,7 +8,8 @@ const envs = { NCHAN: 'disable', PATHS_STATES: path.resolve(__dirname, './dev/states'), PATHS_DYNAMIX_DATA: '/tmp/dynamix/', - PATHS_DYNAMIX_CONFIG: path.resolve(__dirname, './dev/dynamix.cfg') + PATHS_DYNAMIX_CONFIG: path.resolve(__dirname, './dev/dynamix.cfg'), + DEBUG: true }, 'env_safe-mode': { NODE_ENV: 'safe-mode' @@ -39,7 +29,16 @@ const envs = { module.exports = { apps: [{ - ...common, + name: 'graphql-api', + script: path.resolve(__dirname, './index.js'), + watch: false, + wait_ready: true, + listen_timeout: 3000, + exp_backoff_restart_delay: 100, + max_memory_restart: '200M', + env: { + PROCESS_TITLE: 'graphql-api' + }, ...envs }] }; diff --git a/index.js b/index.js index 84f2e417f..868380a71 100644 --- a/index.js +++ b/index.js @@ -1,40 +1,8 @@ -// @ts-check -const os = require('os'); -const path = require('path'); -const Sentry = require('@sentry/node'); -const package = require('./package.json'); -const { main } = package; - -// Send errors to server if enabled -Sentry.init({ - dsn: process.env.SENTRY_DSN, - tracesSampleRate: 1.0, - release: require('./package.json').version, - environment: process.env.NODE_ENV, - serverName: os.hostname(), - enabled: Boolean(process.env.SENTRY_DSN) -}); - -if (!main) { - throw new Error('Missing main field in package.json'); -} - -// Show real stack trace in development -if (process.env.NODE_ENV === 'development') { - try { - require('source-map-support').install({ - handleUncaughtExceptions: false - }); - } catch { - console.error(`Could not load "source-map-support", do you have it installed?`); - } -} - +// If this isn't installed we'll just ignore it try { - const mainPath = path.resolve(__dirname, main); - require(mainPath); -} catch (error) { - Sentry.captureException(error); - console.error(error.message); - process.exit(1); -} \ No newline at end of file + require('source-map-support').install({ + handleUncaughtExceptions: false + }); +} catch {} + +require('./dist/index'); \ No newline at end of file