mirror of
https://github.com/nodemailer/wildduck.git
synced 2026-01-21 00:41:49 +08:00
210 lines
6.1 KiB
JavaScript
210 lines
6.1 KiB
JavaScript
/* eslint global-require:0 */
|
||
|
||
'use strict';
|
||
|
||
process.env.UV_THREADPOOL_SIZE = 16;
|
||
|
||
/*
|
||
* FIXME: Restify depends on `spdy`, which in turn depends on `http-deceiver`,
|
||
* which uses the legacy C library `http_parser`.
|
||
*
|
||
* Newer versions of Node.js have removed `http_parser` in favor of
|
||
* modern APIs. Unfortunately:
|
||
* - `http-deceiver` was last updated ~9 years ago,
|
||
* - `spdy` ~5 years ago,
|
||
* - Restify itself ~2 years ago.
|
||
*
|
||
* As a result, these outdated libraries haven’t been replaced.
|
||
*
|
||
* Quick fix: polyfill `http_parser`.
|
||
* Possible Long-term fix: fork Restify and remove/replace the outdated deps.
|
||
*/
|
||
const originalBinding = process.binding;
|
||
process.binding = function (name) {
|
||
if (name === 'http_parser') {
|
||
return require('http-parser-js');
|
||
}
|
||
return originalBinding.call(process, name);
|
||
};
|
||
const v8 = require('node:v8');
|
||
const Path = require('path');
|
||
const os = require('os');
|
||
const config = require('@zone-eu/wild-config');
|
||
|
||
if (process.env.NODE_CONFIG_ONLY === 'true') {
|
||
console.log(require('util').inspect(config, false, 22)); // eslint-disable-line
|
||
return process.exit();
|
||
}
|
||
|
||
const errors = require('./lib/errors');
|
||
const fs = require('fs');
|
||
const log = require('npmlog');
|
||
const packageData = require('./package.json');
|
||
const { init: initElasticSearch } = require('./lib/elasticsearch');
|
||
|
||
log.level = config.log.level;
|
||
|
||
const printLogo = () => {
|
||
let logo = fs
|
||
.readFileSync(__dirname + '/logo.txt', 'utf-8')
|
||
.replace(/^\n+|\n+$/g, '')
|
||
.split('\n');
|
||
|
||
let columnLength = logo.map(l => l.length).reduce((max, val) => (val > max ? val : max), 0);
|
||
let versionString = ' ' + packageData.name + '@' + packageData.version + ' ';
|
||
let versionPrefix = '-'.repeat(Math.round(columnLength / 2 - versionString.length / 2));
|
||
let versionSuffix = '-'.repeat(columnLength - versionPrefix.length - versionString.length);
|
||
|
||
log.info('App', ' ' + '-'.repeat(columnLength));
|
||
log.info('App', '');
|
||
|
||
logo.forEach(line => {
|
||
log.info('App', ' ' + line);
|
||
});
|
||
|
||
log.info('App', '');
|
||
|
||
log.info('App', ' ' + versionPrefix + versionString + versionSuffix);
|
||
log.info('App', '');
|
||
};
|
||
|
||
let processCount = config.processes;
|
||
if (processCount) {
|
||
if (/^\s*cpus\s*$/i.test(processCount)) {
|
||
processCount = os.cpus().length;
|
||
}
|
||
|
||
if (typeof processCount !== 'number' && !isNaN(processCount)) {
|
||
processCount = Number(processCount);
|
||
}
|
||
|
||
if (isNaN(processCount)) {
|
||
processCount = 1;
|
||
}
|
||
}
|
||
|
||
if (!processCount || processCount <= 1) {
|
||
printLogo();
|
||
if (config.ident) {
|
||
process.title = config.ident;
|
||
}
|
||
// single process mode, do not fork anything
|
||
|
||
initElasticSearch()
|
||
.then(started => {
|
||
if (started) {
|
||
log.verbose('App', `ElasticSearch setup checked`);
|
||
}
|
||
})
|
||
.catch(err => {
|
||
log.error('App', `ElasticSearch setup failed: ${err.message}${err.meta?.statusCode ? ` (${err.meta?.statusCode})` : ''}`);
|
||
})
|
||
.finally(() => {
|
||
require('./worker.js');
|
||
});
|
||
} else {
|
||
let cluster = require('cluster');
|
||
|
||
if (cluster.isMaster) {
|
||
printLogo();
|
||
|
||
if (config.ident) {
|
||
process.title = config.ident + ' master';
|
||
}
|
||
|
||
log.info('App', `Master [${process.pid}] is running`);
|
||
|
||
let workers = new Set();
|
||
|
||
let forkWorker = () => {
|
||
let worker = cluster.fork();
|
||
workers.add(worker);
|
||
log.info('App', `Forked worker ${worker.process.pid}`);
|
||
};
|
||
|
||
// Fork workers.
|
||
initElasticSearch()
|
||
.then(started => {
|
||
if (started) {
|
||
log.verbose('App', `ElasticSearch setup checked`);
|
||
}
|
||
})
|
||
.catch(err => {
|
||
log.error('App', `ElasticSearch setup failed: ${err.message}${err.meta?.statusCode ? ` (${err.meta?.statusCode})` : ''}`);
|
||
})
|
||
.finally(() => {
|
||
for (let i = 0; i < processCount; i++) {
|
||
forkWorker();
|
||
}
|
||
});
|
||
|
||
cluster.on('exit', worker => {
|
||
log.info('App', `Worker ${worker.process.pid} died`);
|
||
workers.delete(worker);
|
||
setTimeout(forkWorker, 1000);
|
||
});
|
||
|
||
config.on('reload', () => {
|
||
workers.forEach(child => {
|
||
try {
|
||
child.kill('SIGHUP');
|
||
} catch (E) {
|
||
//ignore
|
||
}
|
||
});
|
||
});
|
||
} else {
|
||
if (config.ident) {
|
||
process.title = config.ident + ' worker';
|
||
}
|
||
|
||
require('./worker.js');
|
||
}
|
||
}
|
||
|
||
process.on('unhandledRejection', err => {
|
||
log.error('App', 'Unhandled rejection: %s', (err && err.stack) || err);
|
||
errors.notify(err);
|
||
});
|
||
|
||
process.on('SIGHUP', () => {
|
||
// generate memory dump
|
||
log.info('Process', 'PID=%s Generating heap snapshot...', process.pid);
|
||
let stream;
|
||
|
||
try {
|
||
stream = v8.getHeapSnapshot();
|
||
} catch (err) {
|
||
log.error('Process', 'PID=%s Failed to generate heap snapshot: %s', process.pid, err.stack || err);
|
||
return;
|
||
}
|
||
|
||
if (stream) {
|
||
const path = Path.join(
|
||
os.tmpdir(),
|
||
`Heap-${process.pid}-${new Date()
|
||
.toISOString()
|
||
.substring(0, 19)
|
||
.replace(/[^0-9T]+/g, '')}.heapsnapshot`
|
||
);
|
||
|
||
let f;
|
||
try {
|
||
f = fs.createWriteStream(path);
|
||
} catch (err) {
|
||
log.error('Process', 'PID=%s Failed to generate heap snapshot: %s', process.pid, err.stack || err);
|
||
return;
|
||
}
|
||
|
||
f.once('error', err => {
|
||
log.error('Process', 'PID=%s Failed to generate heap snapshot: %s', process.pid, err.stack || err);
|
||
});
|
||
stream.once('error', err => {
|
||
log.error('Process', 'PID=%s Failed to generate heap snapshot: %s', process.pid, err.stack || err);
|
||
});
|
||
stream.pipe(f);
|
||
f.once('finish', () => {
|
||
log.info('Process', 'PID=%s Generated heap snapshot: %s', process.pid, path);
|
||
});
|
||
}
|
||
});
|