-
-
Notifications
You must be signed in to change notification settings - Fork 293
Expand file tree
/
Copy pathindex.ts
More file actions
112 lines (93 loc) · 3.1 KB
/
index.ts
File metadata and controls
112 lines (93 loc) · 3.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import './env';
import './lib/sentry/init';
import { AddressInfo } from 'net';
import os from 'os';
import * as Sentry from '@sentry/node';
import config from 'config';
import express from 'express';
import { isUndefined, toInteger } from 'lodash';
import throng from 'throng';
import setupExpress from './lib/express';
import logger from './lib/logger';
import { reportErrorToSentry } from './lib/sentry';
import { updateCachedFidoMetadata } from './lib/two-factor-authentication/fido-metadata';
import { parseToBoolean } from './lib/utils';
import { startExportWorker } from './workers/exports';
import { startSearchSyncWorker } from './workers/search-sync';
import { sequelize } from './models';
import routes from './routes';
const workers = isUndefined(process.env.WEB_CONCURRENCY) ? toInteger(process.env.WEB_CONCURRENCY) : 1;
async function startExpressServer(workerId) {
const expressApp = express();
await updateCachedFidoMetadata();
await setupExpress(expressApp);
/**
* Routes.
*/
await routes(expressApp);
Sentry.setupExpressErrorHandler(expressApp);
/**
* Start server
*/
const server = expressApp.listen(config.port, () => {
const host = os.hostname();
logger.info(
'Open Collective API listening at http://%s:%s in %s environment. Worker #%s',
host,
(server.address() as AddressInfo).port,
config.env,
workerId,
);
});
server.on('error', error => {
logger.error('Failed to start Express server', error);
reportErrorToSentry(error);
});
server.timeout = 25000; // sets timeout to 25 seconds
expressApp['__server__'] = server;
return expressApp;
}
// Start the express server
let appPromise: Promise<express.Express> | undefined;
if (parseToBoolean(config.services.server)) {
if (['production', 'staging'].includes(config.env) && workers > 1) {
throng({ worker: startExpressServer, count: workers }); // TODO: Thong is not compatible with the shutdown logic below
} else {
appPromise = startExpressServer(1);
}
}
// Start the search sync job
const pStopSearchSyncWorker = startSearchSyncWorker();
const pStopExportWorker = startExportWorker();
let isShuttingDown = false;
const gracefullyShutdown = async signal => {
if (!isShuttingDown) {
logger.info(`Received ${signal}. Shutting down.`);
isShuttingDown = true;
const stopSearchSyncWorker = await pStopSearchSyncWorker;
if (stopSearchSyncWorker) {
await stopSearchSyncWorker();
}
const stopExportWorker = await pStopExportWorker;
if (stopExportWorker) {
await stopExportWorker();
}
if (appPromise) {
await appPromise.then(app => {
if (app['__server__']) {
logger.info('Closing express server');
app['__server__'].close();
}
});
}
await sequelize.close();
process.exit();
}
};
process.on('exit', () => gracefullyShutdown('exit'));
process.on('SIGINT', () => gracefullyShutdown('SIGINT'));
process.on('SIGTERM', () => gracefullyShutdown('SIGTERM'));
// This is used by tests
export default async function startServerForTest() {
return appPromise ?? startExpressServer(1);
}