Finalize log stream before exiting process
Reviewed By: antonk52 Differential Revision: D51229230 fbshipit-source-id: 0e7f657a170eb8602ade9abf1db1976c5b51dc3f
This commit is contained in:
committed by
Facebook GitHub Bot
parent
0cbd640e5c
commit
a400eb2872
@@ -583,6 +583,7 @@ export class FlipperServerImpl implements FlipperServer {
|
|||||||
return uploadRes;
|
return uploadRes;
|
||||||
},
|
},
|
||||||
shutdown: async () => {
|
shutdown: async () => {
|
||||||
|
// Do not use processExit helper. We want to server immediatelly quit when this call is triggerred
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
},
|
},
|
||||||
'is-logged-in': async () => {
|
'is-logged-in': async () => {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export * from './tracker';
|
|||||||
export {loadLauncherSettings} from './utils/launcherSettings';
|
export {loadLauncherSettings} from './utils/launcherSettings';
|
||||||
export {loadProcessConfig} from './utils/processConfig';
|
export {loadProcessConfig} from './utils/processConfig';
|
||||||
export {getEnvironmentInfo} from './utils/environmentInfo';
|
export {getEnvironmentInfo} from './utils/environmentInfo';
|
||||||
|
export {processExit, setProcessExitRoutine} from './utils/processExit';
|
||||||
export {getGatekeepers} from './gk';
|
export {getGatekeepers} from './gk';
|
||||||
export {setupPrefetcher} from './fb-stubs/Prefetcher';
|
export {setupPrefetcher} from './fb-stubs/Prefetcher';
|
||||||
export * from './server/attachSocketServer';
|
export * from './server/attachSocketServer';
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import {URLSearchParams} from 'url';
|
|||||||
import {tracker} from '../tracker';
|
import {tracker} from '../tracker';
|
||||||
import {getFlipperServerConfig} from '../FlipperServerConfig';
|
import {getFlipperServerConfig} from '../FlipperServerConfig';
|
||||||
import {performance} from 'perf_hooks';
|
import {performance} from 'perf_hooks';
|
||||||
|
import {processExit} from '../utils/processExit';
|
||||||
|
|
||||||
const safe = (f: () => void) => {
|
const safe = (f: () => void) => {
|
||||||
try {
|
try {
|
||||||
@@ -266,7 +267,7 @@ export function attachSocketServer(
|
|||||||
console.info(
|
console.info(
|
||||||
'[flipper-server] Shutdown as no clients are currently connected',
|
'[flipper-server] Shutdown as no clients are currently connected',
|
||||||
);
|
);
|
||||||
process.exit(0);
|
processExit(0);
|
||||||
}
|
}
|
||||||
}, FIVE_HOURS);
|
}, FIVE_HOURS);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {EnvironmentInfo, isProduction} from 'flipper-common';
|
|||||||
import {GRAPH_SECRET} from '../fb-stubs/constants';
|
import {GRAPH_SECRET} from '../fb-stubs/constants';
|
||||||
import {sessionId} from '../sessionId';
|
import {sessionId} from '../sessionId';
|
||||||
import {UIPreference, openUI} from '../utils/openUI';
|
import {UIPreference, openUI} from '../utils/openUI';
|
||||||
|
import {processExit} from '../utils/processExit';
|
||||||
|
|
||||||
type Config = {
|
type Config = {
|
||||||
port: number;
|
port: number;
|
||||||
@@ -123,7 +124,7 @@ export async function startServer(
|
|||||||
console.error(
|
console.error(
|
||||||
`[flipper-server] Unable to become ready within ${timeoutSeconds} seconds, exit`,
|
`[flipper-server] Unable to become ready within ${timeoutSeconds} seconds, exit`,
|
||||||
);
|
);
|
||||||
process.exit(1);
|
processExit(1);
|
||||||
}
|
}
|
||||||
}, timeoutSeconds * 1000);
|
}, timeoutSeconds * 1000);
|
||||||
|
|
||||||
@@ -192,6 +193,7 @@ async function startHTTPServer(
|
|||||||
res.json({success: true});
|
res.json({success: true});
|
||||||
|
|
||||||
// Just exit the process, this will trigger the shutdown hooks.
|
// Just exit the process, this will trigger the shutdown hooks.
|
||||||
|
// Do not use prcoessExit util as we want the serve to shutdown immediately
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -226,7 +228,7 @@ async function startHTTPServer(
|
|||||||
`[flipper-server] Unable to listen at port: ${config.port}, is already in use`,
|
`[flipper-server] Unable to listen at port: ${config.port}, is already in use`,
|
||||||
);
|
);
|
||||||
tracker.track('server-socket-already-in-use', {});
|
tracker.track('server-socket-already-in-use', {});
|
||||||
process.exit(1);
|
processExit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,9 @@ export async function checkServerRunning(
|
|||||||
port: number,
|
port: number,
|
||||||
): Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`http://localhost:${port}/info`);
|
const response = await fetch(`http://localhost:${port}/info`, {
|
||||||
|
timeout: 1000,
|
||||||
|
});
|
||||||
if (response.status >= 200 && response.status < 300) {
|
if (response.status >= 200 && response.status < 300) {
|
||||||
const environmentInfo: EnvironmentInfo = await response.json();
|
const environmentInfo: EnvironmentInfo = await response.json();
|
||||||
return environmentInfo.appVersion;
|
return environmentInfo.appVersion;
|
||||||
@@ -74,7 +76,9 @@ export async function checkServerRunning(
|
|||||||
*/
|
*/
|
||||||
export async function shutdownRunningInstance(port: number): Promise<boolean> {
|
export async function shutdownRunningInstance(port: number): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`http://localhost:${port}/shutdown`);
|
const response = await fetch(`http://localhost:${port}/shutdown`, {
|
||||||
|
timeout: 1000,
|
||||||
|
});
|
||||||
if (response.status >= 200 && response.status < 300) {
|
if (response.status >= 200 && response.status < 300) {
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
console.info(
|
console.info(
|
||||||
|
|||||||
44
desktop/flipper-server-core/src/utils/processExit.tsx
Normal file
44
desktop/flipper-server-core/src/utils/processExit.tsx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
const onBeforeExitFns: (() => void | Promise<void>)[] = [];
|
||||||
|
export const setProcessExitRoutine = (
|
||||||
|
onBeforeExit: () => void | Promise<void>,
|
||||||
|
) => {
|
||||||
|
onBeforeExitFns.push(onBeforeExit);
|
||||||
|
};
|
||||||
|
|
||||||
|
const resIsPromise = (res: void | Promise<void>): res is Promise<void> =>
|
||||||
|
res instanceof Promise;
|
||||||
|
export const processExit = async (code: number) => {
|
||||||
|
console.debug('processExit', code);
|
||||||
|
|
||||||
|
// eslint-disable-next-line promise/catch-or-return
|
||||||
|
await Promise.all(
|
||||||
|
onBeforeExitFns.map(async (fn) => {
|
||||||
|
try {
|
||||||
|
const res = fn();
|
||||||
|
if (resIsPromise(res)) {
|
||||||
|
return res.catch((e) => {
|
||||||
|
console.error('Process exit routine failed', e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Process exit routine failed', e);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
).finally(() => {
|
||||||
|
process.exit(code);
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
console.error('Process exit routines timed out');
|
||||||
|
process.exit(code);
|
||||||
|
}, 5000);
|
||||||
|
};
|
||||||
@@ -30,6 +30,7 @@ import {
|
|||||||
startFlipperServer,
|
startFlipperServer,
|
||||||
startServer,
|
startServer,
|
||||||
tracker,
|
tracker,
|
||||||
|
processExit,
|
||||||
} from 'flipper-server-core';
|
} from 'flipper-server-core';
|
||||||
import {addLogTailer, isProduction, isTest, LoggerFormat} from 'flipper-common';
|
import {addLogTailer, isProduction, isTest, LoggerFormat} from 'flipper-common';
|
||||||
import exitHook from 'exit-hook';
|
import exitHook from 'exit-hook';
|
||||||
@@ -265,7 +266,7 @@ async function start() {
|
|||||||
console.error(
|
console.error(
|
||||||
'[flipper-server] state changed to error, process will exit.',
|
'[flipper-server] state changed to error, process will exit.',
|
||||||
);
|
);
|
||||||
process.exit(1);
|
processExit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -335,7 +336,7 @@ process.on('uncaughtException', (error) => {
|
|||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
reportBrowserConnection(false);
|
reportBrowserConnection(false);
|
||||||
process.exit(1);
|
processExit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on('unhandledRejection', (reason, promise) => {
|
process.on('unhandledRejection', (reason, promise) => {
|
||||||
@@ -347,8 +348,15 @@ process.on('unhandledRejection', (reason, promise) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
start().catch((e) => {
|
// Node.js process never waits for all promises to settle and exits as soon as there is not pending timers or open sockets or tasks in teh macroqueue
|
||||||
|
const runtimeTimeout = setTimeout(() => {}, Number.MAX_SAFE_INTEGER);
|
||||||
|
// eslint-disable-next-line promise/catch-or-return
|
||||||
|
start()
|
||||||
|
.catch((e) => {
|
||||||
console.error(chalk.red('Server startup error: '), e);
|
console.error(chalk.red('Server startup error: '), e);
|
||||||
reportBrowserConnection(false);
|
reportBrowserConnection(false);
|
||||||
process.exit(1);
|
return processExit(1);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
clearTimeout(runtimeTimeout);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,7 +21,10 @@ import fsRotator from 'file-stream-rotator';
|
|||||||
import {ensureFile} from 'fs-extra';
|
import {ensureFile} from 'fs-extra';
|
||||||
import {access} from 'fs/promises';
|
import {access} from 'fs/promises';
|
||||||
import {constants} from 'fs';
|
import {constants} from 'fs';
|
||||||
import {initializeLogger as initLogger} from 'flipper-server-core';
|
import {
|
||||||
|
initializeLogger as initLogger,
|
||||||
|
setProcessExitRoutine,
|
||||||
|
} from 'flipper-server-core';
|
||||||
|
|
||||||
export const loggerOutputFile = 'flipper-server-log.out';
|
export const loggerOutputFile = 'flipper-server-log.out';
|
||||||
|
|
||||||
@@ -64,4 +67,14 @@ export async function initializeLogger(
|
|||||||
logStream?.write(`${name}: \n${stack}\n`);
|
logStream?.write(`${name}: \n${stack}\n`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const finalizeLogger = async () => {
|
||||||
|
const logStreamToEnd = logStream;
|
||||||
|
// Prevent future writes
|
||||||
|
logStream = undefined;
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
logStreamToEnd?.end(resolve);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
setProcessExitRoutine(finalizeLogger);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user