mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
多线程(cluster)
This commit is contained in:
1 parent
1c8b62a6d9
commit
45f1184d68
7 files changed
+169
-73
No files matched your search
@@ -22,8 +22,8 @@ jobs:
|
|||||||
yarn build:production
|
yarn build:production
|
||||||
- uses: actions/upload-artifact@v1
|
- uses: actions/upload-artifact@v1
|
||||||
with:
|
with:
|
||||||
name: development.js
|
name: app.js
|
||||||
path: .build/development.js
|
path: .build/app.js
|
||||||
- uses: actions/upload-artifact@v1
|
- uses: actions/upload-artifact@v1
|
||||||
with:
|
with:
|
||||||
name: full.js
|
name: full.js
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ Hydro 的界面基于 Vijos 二次开发。
|
|||||||
#### 直接部署:
|
#### 直接部署:
|
||||||
|
|
||||||
安装mongodb (省略)
|
安装mongodb (省略)
|
||||||
下载Github Actions自动编译的 development.js 直接运行即可。
|
下载Github Actions自动编译的 app.js 直接运行即可。
|
||||||
|
|
||||||
## 鸣谢
|
## 鸣谢
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -66,7 +66,7 @@ async function build(type) {
|
|||||||
console.error(`Module pack failed: ${m}`);
|
console.error(`Module pack failed: ${m}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const f = fs.readFileSync(root('.build/development.js')).toString();
|
const f = fs.readFileSync(root('.build/app.js')).toString();
|
||||||
const installer = fs.readFileSync(root('tool/install.js')).toString();
|
const installer = fs.readFileSync(root('tool/install.js')).toString();
|
||||||
const file = `global._hydroModule=${JSON.stringify(j)};${f}`;
|
const file = `global._hydroModule=${JSON.stringify(j)};${f}`;
|
||||||
fs.writeFileSync(root('.build/full.js'), file);
|
fs.writeFileSync(root('.build/full.js'), file);
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ const build = async (type) => {
|
|||||||
const config = {
|
const config = {
|
||||||
mode: type,
|
mode: type,
|
||||||
entry: {
|
entry: {
|
||||||
development: root('hydro/development.js'),
|
app: root('hydro/loader.js'),
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
process.stdin.setEncoding('utf8');
|
|
||||||
process.stdin.on('data', async (input) => {
|
|
||||||
try {
|
|
||||||
const t = eval(input.toString().trim()); // eslint-disable-line no-eval
|
|
||||||
if (t instanceof Promise) console.log(await t);
|
|
||||||
else console.log(t);
|
|
||||||
} catch (e) {
|
|
||||||
console.warn(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
process.on('unhandledRejection', (e) => console.log(e));
|
|
||||||
|
|
||||||
global.onDestory = [];
|
|
||||||
async function terminate() {
|
|
||||||
for (const task of global.onDestory) {
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
|
||||||
await task();
|
|
||||||
}
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
process.on('SIGINT', terminate);
|
|
||||||
|
|
||||||
require('./loader').load().catch((e) => {
|
|
||||||
console.error(e);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
+161
-39
@@ -5,6 +5,8 @@ const fs = require('fs');
|
|||||||
const os = require('os');
|
const os = require('os');
|
||||||
const zlib = require('zlib');
|
const zlib = require('zlib');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const cluster = require('cluster');
|
||||||
|
const numCPUs = require('os').cpus().length;
|
||||||
const yaml = require('js-yaml');
|
const yaml = require('js-yaml');
|
||||||
|
|
||||||
function ensureDir(dir) {
|
function ensureDir(dir) {
|
||||||
@@ -31,12 +33,9 @@ if (global._hydroModule) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function preload() {
|
async function unzip() {
|
||||||
for (const i of pending) {
|
for (const i of pending) {
|
||||||
try {
|
try {
|
||||||
if (i.os) {
|
|
||||||
if (!i.os.includes(os.platform().toLowerCase())) throw new Error('Unsupported OS');
|
|
||||||
}
|
|
||||||
if (i.file) {
|
if (i.file) {
|
||||||
i.files = {};
|
i.files = {};
|
||||||
ensureDir(path.resolve(os.tmpdir(), 'hydro', i.id));
|
ensureDir(path.resolve(os.tmpdir(), 'hydro', i.id));
|
||||||
@@ -59,6 +58,21 @@ async function preload() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function preload() {
|
||||||
|
for (const i of pending) {
|
||||||
|
try {
|
||||||
|
if (i.os) {
|
||||||
|
if (!i.os.includes(os.platform().toLowerCase())) throw new Error('Unsupported OS');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
i.fail = true;
|
||||||
|
fail.push(i.id);
|
||||||
|
console.error(`Module Load Fail: ${i.id}`);
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function handler() {
|
async function handler() {
|
||||||
for (const i of pending) {
|
for (const i of pending) {
|
||||||
if (i.handler && !i.fail) {
|
if (i.handler && !i.fail) {
|
||||||
@@ -182,23 +196,33 @@ async function install() {
|
|||||||
await setup.setup();
|
await setup.setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function load() {
|
const builtinLib = [
|
||||||
|
'axios', 'download', 'i18n', 'mail', 'markdown',
|
||||||
|
'md5', 'misc', 'paginate', 'hash.hydro', 'rank',
|
||||||
|
'template', 'validator', 'nav', 'sysinfo',
|
||||||
|
];
|
||||||
|
|
||||||
|
const builtinModel = [
|
||||||
|
'builtin', 'document', 'domain', 'blacklist', 'opcount',
|
||||||
|
'setting', 'token', 'user', 'problem', 'record',
|
||||||
|
'contest', 'message', 'solution', 'training', 'file',
|
||||||
|
'discussion', 'system',
|
||||||
|
];
|
||||||
|
|
||||||
|
const builtinHandler = [
|
||||||
|
'home', 'problem', 'record', 'judge', 'user',
|
||||||
|
'contest', 'training', 'discussion', 'manage', 'import',
|
||||||
|
'misc', 'homework', 'domain',
|
||||||
|
];
|
||||||
|
|
||||||
|
const builtinScript = [
|
||||||
|
'install', 'uninstall', 'rating', 'recalcRating',
|
||||||
|
];
|
||||||
|
|
||||||
|
async function loadAsMaster() {
|
||||||
ensureDir(path.resolve(os.tmpdir(), 'hydro'));
|
ensureDir(path.resolve(os.tmpdir(), 'hydro'));
|
||||||
global.Hydro = {
|
|
||||||
handler: {},
|
|
||||||
service: {},
|
|
||||||
model: {},
|
|
||||||
script: {},
|
|
||||||
lib: {},
|
|
||||||
nodeModules: {
|
|
||||||
bson: require('bson'),
|
|
||||||
'js-yaml': require('js-yaml'),
|
|
||||||
mongodb: require('mongodb'),
|
|
||||||
},
|
|
||||||
template: {},
|
|
||||||
ui: {},
|
|
||||||
};
|
|
||||||
pending.push(...await require('./lib/hpm').getInstalled());
|
pending.push(...await require('./lib/hpm').getInstalled());
|
||||||
|
await unzip();
|
||||||
await preload();
|
await preload();
|
||||||
require('./lib/i18n');
|
require('./lib/i18n');
|
||||||
require('./utils');
|
require('./utils');
|
||||||
@@ -221,11 +245,6 @@ async function load() {
|
|||||||
bus.subscribe(['system_database_connected'], h);
|
bus.subscribe(['system_database_connected'], h);
|
||||||
require('./service/db');
|
require('./service/db');
|
||||||
});
|
});
|
||||||
const builtinLib = [
|
|
||||||
'axios', 'download', 'i18n', 'mail', 'markdown',
|
|
||||||
'md5', 'misc', 'paginate', 'hash.hydro', 'rank',
|
|
||||||
'template', 'validator', 'nav', 'sysinfo',
|
|
||||||
];
|
|
||||||
for (const i of builtinLib) require(`./lib/${i}`);
|
for (const i of builtinLib) require(`./lib/${i}`);
|
||||||
await lib();
|
await lib();
|
||||||
require('./service/gridfs');
|
require('./service/gridfs');
|
||||||
@@ -233,12 +252,6 @@ async function load() {
|
|||||||
const server = require('./service/server');
|
const server = require('./service/server');
|
||||||
await server.prepare();
|
await server.prepare();
|
||||||
await service();
|
await service();
|
||||||
const builtinModel = [
|
|
||||||
'builtin', 'document', 'domain', 'blacklist', 'opcount',
|
|
||||||
'setting', 'token', 'user', 'problem', 'record',
|
|
||||||
'contest', 'message', 'solution', 'training', 'file',
|
|
||||||
'discussion',
|
|
||||||
];
|
|
||||||
for (const i of builtinModel) {
|
for (const i of builtinModel) {
|
||||||
const m = require(`./model/${i}`);
|
const m = require(`./model/${i}`);
|
||||||
if (m.ensureIndexes) await m.ensureIndexes();
|
if (m.ensureIndexes) await m.ensureIndexes();
|
||||||
@@ -247,13 +260,8 @@ async function load() {
|
|||||||
const dbVer = await system.get('db.ver');
|
const dbVer = await system.get('db.ver');
|
||||||
if (dbVer !== 1) {
|
if (dbVer !== 1) {
|
||||||
const ins = require('./script/install');
|
const ins = require('./script/install');
|
||||||
await ins.run('Root', 'rootroot');
|
await ins.run({ username: 'Root', password: 'rootroot' });
|
||||||
}
|
}
|
||||||
const builtinHandler = [
|
|
||||||
'home', 'problem', 'record', 'judge', 'user',
|
|
||||||
'contest', 'training', 'discussion', 'manage', 'import',
|
|
||||||
'misc', 'homework', 'domain',
|
|
||||||
];
|
|
||||||
for (const i of builtinHandler) require(`./handler/${i}`);
|
for (const i of builtinHandler) require(`./handler/${i}`);
|
||||||
await model();
|
await model();
|
||||||
await handler();
|
await handler();
|
||||||
@@ -271,15 +279,129 @@ async function load() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const builtinScript = [
|
for (const i of builtinScript) require(`./script/${i}`);
|
||||||
'install', 'uninstall', 'rating', 'recalcRating',
|
await script();
|
||||||
];
|
pending = [];
|
||||||
|
await server.start(await system.get('server.port'));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadAsWorker() {
|
||||||
|
pending.push(...await require('./lib/hpm').getInstalled());
|
||||||
|
await preload();
|
||||||
|
require('./lib/i18n');
|
||||||
|
require('./utils');
|
||||||
|
require('./error');
|
||||||
|
require('./permission');
|
||||||
|
require('./options');
|
||||||
|
await Promise.all([locale(), template()]);
|
||||||
|
const bus = require('./service/bus');
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
const h = () => {
|
||||||
|
console.log('Database connected');
|
||||||
|
bus.unsubscribe(['system_database_connected'], h);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
bus.subscribe(['system_database_connected'], h);
|
||||||
|
require('./service/db');
|
||||||
|
});
|
||||||
|
for (const i of builtinLib) require(`./lib/${i}`);
|
||||||
|
await lib();
|
||||||
|
require('./service/gridfs');
|
||||||
|
const server = require('./service/server');
|
||||||
|
await server.prepare();
|
||||||
|
await service();
|
||||||
|
for (const i of builtinModel) require(`./model/${i}`);
|
||||||
|
for (const i of builtinHandler) require(`./handler/${i}`);
|
||||||
|
await model();
|
||||||
|
await handler();
|
||||||
|
for (const i in global.Hydro.handler) {
|
||||||
|
await global.Hydro.handler[i]();
|
||||||
|
}
|
||||||
|
const notfound = require('./handler/notfound');
|
||||||
|
await notfound();
|
||||||
|
for (const i in global.Hydro.service) {
|
||||||
|
if (global.Hydro.service[i].postInit) {
|
||||||
|
try {
|
||||||
|
await global.Hydro.service[i].postInit();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
for (const i of builtinScript) require(`./script/${i}`);
|
for (const i of builtinScript) require(`./script/${i}`);
|
||||||
await script();
|
await script();
|
||||||
pending = [];
|
pending = [];
|
||||||
await server.start();
|
await server.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function terminate() {
|
||||||
|
for (const task of global.onDestory) {
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
await task();
|
||||||
|
}
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function load() {
|
||||||
|
global.Hydro = {
|
||||||
|
handler: {},
|
||||||
|
service: {},
|
||||||
|
model: {},
|
||||||
|
script: {},
|
||||||
|
lib: {},
|
||||||
|
nodeModules: {
|
||||||
|
bson: require('bson'),
|
||||||
|
'js-yaml': require('js-yaml'),
|
||||||
|
mongodb: require('mongodb'),
|
||||||
|
},
|
||||||
|
template: {},
|
||||||
|
ui: {},
|
||||||
|
};
|
||||||
|
global.onDestory = [];
|
||||||
|
if (cluster.isMaster) {
|
||||||
|
console.log(`Master ${process.pid} Starting`);
|
||||||
|
process.stdin.setEncoding('utf8');
|
||||||
|
process.stdin.on('data', async (input) => {
|
||||||
|
try {
|
||||||
|
const t = eval(input.toString().trim()); // eslint-disable-line no-eval
|
||||||
|
if (t instanceof Promise) console.log(await t);
|
||||||
|
else console.log(t);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
process.on('unhandledRejection', (e) => console.log(e));
|
||||||
|
process.on('SIGINT', terminate);
|
||||||
|
await loadAsMaster();
|
||||||
|
cluster.on('exit', (worker, code, signal) => {
|
||||||
|
console.log(`Worker ${worker.process.pid} exit: ${code} ${signal}`);
|
||||||
|
});
|
||||||
|
cluster.on('disconnect', (worker) => {
|
||||||
|
console.log(`Worker ${worker.process.pid} disconnected`);
|
||||||
|
});
|
||||||
|
cluster.on('listening', (worker, address) => {
|
||||||
|
console.log(`Worker ${worker.process.pid} listening at `, address);
|
||||||
|
});
|
||||||
|
cluster.on('online', (worker) => {
|
||||||
|
console.log(`Worker ${worker.process.pid} is online`);
|
||||||
|
});
|
||||||
|
for (let i = 0; i < numCPUs; i++) {
|
||||||
|
cluster.fork();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log(`Worker ${process.pid} Starting`);
|
||||||
|
await loadAsWorker();
|
||||||
|
console.log(`Worker ${process.pid} Started`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
load, pending, active, fail,
|
load, pending, active, fail,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!module.parent) {
|
||||||
|
load().catch((e) => {
|
||||||
|
console.error(e);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -438,12 +438,12 @@ function Validate(key, func) {
|
|||||||
else validate[key] = [func];
|
else validate[key] = [func];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function start() {
|
async function start(port) {
|
||||||
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
|
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
|
||||||
app.use(router.routes()).use(router.allowedMethods());
|
app.use(router.routes()).use(router.allowedMethods());
|
||||||
Route('*', Handler);
|
Route('*', Handler);
|
||||||
server.listen(await system.get('server.port'));
|
server.listen(port);
|
||||||
console.log('Server listening at: %s', await system.get('server.port'));
|
if (port) console.log('Server listening at: %s', port);
|
||||||
}
|
}
|
||||||
|
|
||||||
global.Hydro.service.server = module.exports = {
|
global.Hydro.service.server = module.exports = {
|
||||||
|
|||||||
Reference in new issue
Block a user