-
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathapp.js
More file actions
170 lines (154 loc) · 4.45 KB
/
Copy pathapp.js
File metadata and controls
170 lines (154 loc) · 4.45 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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/**
* Module dependencies.
*/
import chalk from 'chalk';
import nodeHttp from 'http';
import nodeHttps from 'https';
import config from '../config/index.js';
import express from './services/express.js';
import mongooseService from './services/mongoose.js';
import migrations from './services/migrations.js';
import AnalyticsService from './services/analytics.js';
import SentryService from './services/sentry.js';
// Establish an SQL server connection, instantiating all models and schemas
// const startSequelize = () =>
// new Promise(async (resolve, reject) => {
// let orm = {};
// if (config.orm) {
// try {
// orm = await import(path.resolve('./services/sequelize.js'));
// orm.sync().then(() => {
// resolve(orm);
// });
// } catch (e) {
// console.log(e);
// reject(e);
// }
// } else {
// resolve();
// }
// });
// Establish a MongoDB connection, instantiating all models
const startMongoose = async () => {
try {
await mongooseService.loadModels();
const connection = await mongooseService.connect();
return connection;
} catch (e) {
throw new Error(e);
}
};
/**
* Establish ExpressJS powered web server
* @return {object} app
*/
const startExpress = async () => {
try {
const app = await express.init();
return app;
} catch (e) {
throw new Error(e);
}
};
/**
* Bootstrap the required services
* @return {Object} db, orm, and app instances
*/
const bootstrap = async () => {
let orm;
let db;
let app;
// try {
// orm = await startSequelize();
// } catch (e) {
// orm = {};
// }
try {
await SentryService.init();
db = await startMongoose();
await migrations.run();
app = await startExpress();
} catch (e) {
throw new Error(`unable to initialize Mongoose or ExpressJS : ${e}`);
}
return {
db,
orm,
app,
};
};
/**
* log server configuration
*/
const logConfiguration = () => {
// Create server URL
const server = `${(config.secure && config.secure.credentials ? 'https://' : 'http://') + config.api.host}:${config.api.port}`;
// Logging initialization
console.log(chalk.green(config.app.title));
console.log();
console.log(chalk.green(`Environment: ${process.env.NODE_ENV ? process.env.NODE_ENV : 'develoment'}`));
console.log(chalk.green(`Server: ${server}`));
console.log(chalk.green(`Database: ${config.db.uri}`));
if (config.cors.origin.length > 0) console.log(chalk.green(`Cors: ${config.cors.origin}`));
};
// Boot up the server
const start = async () => {
let db;
let orm;
let app;
let http;
try {
({ db, orm, app } = await bootstrap());
} catch (e) {
throw new Error(e);
}
try {
if (config.secure && config.secure.credentials)
http = await nodeHttps.createServer(config.secure.credentials, app).setTimeout(config.api.timeout).listen(config.api.port, config.api.host);
else http = await nodeHttp.createServer(app).setTimeout(config.api.timeout).listen(config.api.port, config.api.host);
logConfiguration();
return {
db,
orm,
app,
http,
};
} catch (e) {
throw new Error(e);
}
};
const FORCE_SHUTDOWN_TIMEOUT_MS = 5000;
/**
* Gracefully shut down the server, disconnecting services before exiting.
* If the server promise rejects (e.g. failed to start), logs the error and exits.
* A forced exit is triggered after {@link FORCE_SHUTDOWN_TIMEOUT_MS} ms if shutdown hangs.
*
* @param {Promise<{http: import('http').Server}>} server - Promise returned by {@link start}
* @returns {Promise<void>} Resolves when shutdown is initiated (process exits via callback)
*/
const shutdown = async (server) => {
// Force exit if graceful shutdown hangs
const forceTimeout = setTimeout(() => {
console.error(chalk.red('Forced shutdown (timeout)'));
process.exit(1);
}, FORCE_SHUTDOWN_TIMEOUT_MS);
forceTimeout.unref();
try {
const value = await server;
await AnalyticsService.shutdown();
await SentryService.shutdown();
await mongooseService.disconnect();
value.http.close((err) => {
console.info(chalk.yellow('Server closed'));
if (err) {
console.info(chalk.red('Error on server close.', err));
process.exitCode = 1;
}
process.exit();
});
} catch (err) {
console.error(chalk.red('Shutdown error: server never started or shutdown failed'), err);
process.exit(1);
}
};
export { bootstrap, start, shutdown };