Add concurrent setting

This commit is contained in:
1computer1 2019-05-17 01:55:24 -04:00
parent 990143864e
commit e8b9303b4c
4 changed files with 66 additions and 19 deletions

View file

@ -119,6 +119,7 @@ The container is locked down, so there is no networking, limited memory and CPU
- `memory` Max memory usage of a container.
- `cpu` Max CPU usage of a container.
- `timeout` Time limit for code in milliseconds.
- `prepare` Whether to run containers on setup.
- `prepare` Whether to start containers on setup.
Setting to true will speed up the first eval, but that language might not be used.
- `concurrent` Number of code evaluations per language than can run at a time.
0. Run `node .`

View file

@ -11,5 +11,6 @@
"memory": "256m",
"cpus": "0.25",
"timeout": 10000,
"prepare": false
"prepare": false,
"concurrent": 10
}

View file

@ -1,6 +1,7 @@
const { AkairoHandler } = require('discord-akairo');
const { Collection } = require('discord.js');
const Language = require('./Language');
const Queue = require('./Queue');
const childProcess = require('child_process');
const util = require('util');
const path = require('path');
@ -24,6 +25,7 @@ class LanguageHandler extends AkairoHandler {
this.aliases = new Collection();
this.containers = new Collection();
this.queues = new Collection();
}
register(language, filepath) {
@ -56,6 +58,7 @@ class LanguageHandler extends AkairoHandler {
return Promise.all(loads.map(async name => {
const folder = path.join(__dirname, '../../docker', name);
await util.promisify(childProcess.exec)(`docker build -t "1computer1/comp_iler:${name}" ${folder}`);
this.queues.set(id, new Queue(10));
if (this.client.config.prepare) {
await this.setupContainer(id);
}
@ -89,10 +92,13 @@ class LanguageHandler extends AkairoHandler {
this.containers.get(id).count += 1;
}
async evalCode({ language, code, options }) {
evalCode({ language, code, options }) {
const { id = language.id, env = {} } = language.runWith(options);
const queue = this.queues.get(id);
return queue.enqueue(async () => {
const { name, count } = await this.setupContainer(id);
this.incrementCount(id);
const proc = childProcess.spawn('docker', [
'exec',
`-eCOUNT=${count}`,
@ -108,6 +114,7 @@ class LanguageHandler extends AkairoHandler {
await this.kill(name);
throw err;
}
});
}
handleSpawn(proc) {

38
src/struct/Queue.js Normal file
View file

@ -0,0 +1,38 @@
class Queue {
constructor(limit) {
this.limit = limit;
this.tasks = [];
this.ongoing = 0;
}
get length() {
return this.tasks.length;
}
enqueue(task) {
return new Promise((resolve, reject) => {
this.tasks.push({ task, resolve, reject });
if (this.ongoing <= this.limit) {
this.process();
}
});
}
async process() {
this.ongoing++;
const { task, resolve, reject } = this.tasks.shift();
try {
const x = await task();
resolve(x);
} catch (e) {
reject(e);
}
this.ongoing--;
while (this.ongoing <= this.limit && this.tasks.length > 0) {
this.process();
}
}
}
module.exports = Queue;