我正在建立一个项目。我现在正在处理的部分应该执行以下操作:
- 使用 ID 和密码登录平台(完成)
- 获取数据数组(暂时硬编码)
- 使用数组的每个元素执行 API 调用,获取每个元素的结果并将其放入另一个数组
- 简而言之,通过传递一个 id 数组作为输入,我应该得到一个结果数组作为输出
为了进一步简化问题,我决定使用一个 id 并将其传递 1000 次,而不是 1000 个不同值的数组。
限制
我可以每分钟调用 API 300 次,否则我会得到著名的“429 问题”->
我的应用程序不使用 express。我正在寻找替代品并遇到了瓶颈包。它完全符合我的需要,并且应该限制 API 调用以及在失败或事件管理的情况下执行重试(请参阅上面链接中的文档)。
这是我到目前为止所拥有的:
const BottleNeck = require('bottleneck');
const logger = require('./functions/logger');
/**
* this reservoir is allowed to execute 300 requests/ minute
*/
const limiter = new BottleNeck({
reservoir: 300, // 300 requests per minute
reservoirRefreshAmount: 249,
reservoirRefreshInterval: 60 * 1000, // must be divisible by 250
trackDoneStatus: true,
minTime: 300//5 requests per second
});
limiter.on("debug", function (message, data) {
// Useful to figure out what the limiter is doing in real time
// and to help debug your application
});
limiter.on("depleted", function (empty) {
logger.info(`BottleNeck() - reservoir is empty. Waiting... ${limiter.options}`);
// This will be called every time the reservoir drops to 0.
// The `empty` (boolean) argument indicates whether `limiter.empty()` is currently true.
});
limiter.on("dropped", function (dropped) {
// This will be called when a strategy was triggered.
// The dropped request is passed to this event listener.
});
limiter.on("empty", function () {
// This will be called when `limiter.empty()` becomes true.
});
limiter.on("error", function (error) {
/* handle errors here */
logger.error(`Limiter : fetched error ${error.message}`);
});
// Listen to the "failed" event
limiter.on("failed", async (error, jobInfo) => {
const id = jobInfo.options.id;
console.warn(`Job ${id} failed: ${error}`);
if (jobInfo.retryCount === 0) { // Here we only retry once
console.log(`Retrying job ${id} in 25ms!`);
return 25;
}
});
limiter.on("idle", function () {
// This will be called when `limiter.empty()` is `true` and `limiter.running()` is `0`.
});
limiter.on("queued", function (info) {
// This event is triggered when a job transitions from one Lifecycle stage to another
});
// Listen to the "retry" event
limiter.on("retry", (error, jobInfo) => console.log(`Now retrying ${jobInfo.options.id}`));
module.exports = { bottleNeck: limiter };
(假设 logger 是使用 logs4js 或任何其他方式定义的。
主要代码:
const { logger } = require("./functions/logger");
const { moment } = require("moment");
const { toCloudLogin, youOnlyHadOneJob } = require("./functions/toCloud");
const { bottleNeck } = require("./apiBottleNeck");
const go = async () => {
try {
logger.info(`hello`);
await toCloudLogin();
logger.info(`starting the bottleneck`);
let counter = 0;
for (let x = 0; x < 310; x++) { //calling same job through bottleneck many times
counter+=1;
let reservoir = await bottleNeck.currentReservoir(); // returns integer of the current
// reservoir api calls left
const result = await bottleNeck.schedule(async () => youOnlyHadOneJob(reservoir));
}
logger.info(`finished the bottleneck` + counter)
} catch (e) {
console.log(e);
logger.error(`error: ${e.message} stack :${e.stack}`);
}
}
go();
以下是我的问题:
如果bottleNeck应该过滤API调用的数量,为什么我仍然得到最大调用堆栈大小超过知道我启动300存储(实际上是301和0)和300充电
我应该如何实现所有这些事件?(例如耗尽:
limiter.on("depleted", function (empty) {
logger.info(`BottleNeck() - reservoir is empty. Waiting... ${limiter.options}`);
// This will be called every time the reservoir drops to 0.
// The `empty` (boolean) argument indicates whether `limiter.empty()` is currently true.
});
)。在我的主要功能中,以便在水库为空时向我发送任何内容。我已经阅读了事件发射器,我认为我应该在某个地方limiter.emit(
耗尽)
,但我不明白如何正确整合它。