这是很难描述的问题。
我有一个koajs
应用,该应用的功能是每2分钟在多个实例(10-1000范围)中创建的。在应用启动时创建的计划作业。我使用koajs
是因为我为此应用程序需要一些简单的api端点。在开始的3-5个小时内运行良好,然后创建的实例数开始减少,某些日志输出消失了。
这是基于实际代码的最少示例:
server.ts
const bootstrap = async () => {
process.setMaxListeners(0); //(node:7310) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 uncaughtException listeners added to [process]. Use emitter.setMaxListeners() to increase limit
//appears on app startup (however seems like this setMaxListeners(0) doesnt affect anything since the warning persist)
const app = new Koa();
app.use(async ctx => {
ctx.body = "Welcome to my Server!";
});
app.listen(port);
new Main().run();
};
bootstrap();
main.ts (尝试使用cron
npm软件包,node-scheduler
,setInterval
,递归setTimeout
)来运行{{1} }。
scheduledJobWrapper
在此示例中,问题表现如下: 预期的所有工作在最初的3-5小时内进行,之后每次计划的功能调用:
isStarting: boolean = false;
async run() {
logger.info(`running the app, every 2 minutes`);
//let that = this;
// new CronJob(`*/2 * * * *`, function () {
// that.scheduledJobWrapper();
// }, null, true, 'America/Los_Angeles');
const interval = 2 * 60 * 1000;
setInterval(() => {
this.scheduledJobWrapper();
}, interval);
}
async scheduledJobWrapper() {
logger.info("here scheduledJobWrapper");
let args = {};
//some irrelevant logic to set the arguments
await this.scheduledJob(args);
}
async scheduledJob(args) {
try {
logger.info("starting");
if (!this.isStarting) {
this.isStarting = true;
const runningCount = Executor.tasks.length; //Executor.tasks is a singleton containing some info about tasks. details are irrelevant. the point is it contains the active tasks.
const tasksLimit = 100;
if (runningCount < tasksLimit) {
for await (const i of Array(tasksLimit - runningCount).keys()) {
if (Executor.tasks.length > 20)
await global.sleep(5 * 1000);
this.startWrapper(args); //calling main task here
}
}
this.isStarting = false;
logger.info(`Started: ${Executor.tasks.length - runningCount}`);
}
} catch (e) {
logger.error("Error running scheduled job: " + e.toString());
}
}
现在不会显示任何输出。logger.info("here scheduledJobWrapper");
不在输出中logger.info("starting");
确实运行,并且其中的代码正在执行。尽管this.startWrapper
内部的代码仍在运行,但是新创建的作业的数量正在缓慢减少。
硬件(RAM / CPU)负载不大(CPU低于10%,RAM低于20%)
关于可能原因的任何线索吗?
谢谢!
更新
似乎使用this.startWrapper
时,该应用程序可以正常运行更长的时间(6-24小时),但此后问题仍然开始。
答案 0 :(得分:1)
问题与setInterval
函数有关。随着时间的流逝,它变得越来越慢。它也有奇怪的行为。您可以使用setTimeout
创建自定义setInterval或使用第三方模块并进行尝试。
setInterval实现示例。
const intervals = new Map();
function setInterval(fn, time, context, ...args) {
const id = new Date().getTime() + "" + Math.floor(Math.random() * 10000);
intervals.set(
id,
setTimeout(function next() {
intervals.set(id, setTimeout(next, time));
fn.apply(context, args);
}, time)
);
return id;
}
function clearInterval(id) {
clearTimeout(intervals.get(id));
}
setInterval(console.log, 100, console, "hi");
您还可以通过在下一个setTimeout中添加增量时间损失来增强功能。 这意味着如果浪费时间,请更早运行下一个setTimeout。
答案 1 :(得分:0)
首先,最好在侦听范围内移动Main()的实例:
app.listen(port, () => {
new Main().run();
});
我不知道在后端运行setInterval函数有什么好主意。最好提取此逻辑并将其移入cron作业。
我们确定机器可以运行100个任务吗?请按顺序计数任务,并查看问题何时开始。可能您无法安排100个任务,并且某个地方存在一个限制