我有一个带有Kafka订阅者的node.js应用。 订阅处理程序使用“ fetch”来调用远程REST API(等待fetch(...))。
我尝试处理大量消息,由于远程服务器超载,REST调用失败。
发生过载是因为订阅者进程是异步的。
我的问题是: 有没有办法确保异步处理程序已序列化,因此不会同时调用远程API服务器?
克里斯: 我正在使用kafka-node
这是一个代码示例:
const consumer = new Consumer(this.client, [{ topic: topicKey}]);
consumer.on('message', function (message) {
handleMessage(message)
});
async function handleMessage(message) {
... decode the message
// Send to the Remote server using a REST call
//=> the task is suspended, waiting for the IO, so, meantime, the next message
// is processed, and I flood the remote server of POST requests.
await fetch(...);
}
谢谢。
答案 0 :(得分:2)
我不确定您想要实现什么。我了解您的API过载,因为您同时进行了太多调用。
因此,如果我的理解很好,则希望同步进行。
正如我在评论中所说,我认为队列是一个不错的选择。这就是我的方法(您可能会找到在其他地方实现队列的更好方法,但是我只是给您一个想法:D)
const consumer = new Consumer(this.client, [{ topic: topicKey}]);
const myQueue = [];
consumer.on('message', function (message) {
myQueue.push(message);
});
async function consumeQueue(){
const message = myQueue.shift();
if(!message){
await sleep(3000);
} else {
// ... decode your message
await fetch(message)
}
consumeQueue();
}
function sleep(ms){
return new Promise(resolve => setTimeout(resolve, ms));
}
// you have to init it :D
consumeQueue();
答案 1 :(得分:0)
如果您只想暂停“流”,直到执行异步代码。由于可读流(ConsumerGroupStream)可以暂停并再次恢复,因此以下方法可以很好地工作。
const kafka = require('kafka-node') const options = { kafkaHost: '127.0.0.1:9092', groupId: 'Group' }; const consumerGroupStream = new kafka.ConsumerGroupStream(options, ['queue']); consumerGroupStream .on('data', (massage) => { consumerGroupStream.pause(); console.log('Message: ', massage, Date.now()); asyncFunction().then(() => { console.log('Now data will start flowing again.', Date.now()); consumerGroupStream.resume(); }); });
第二个选项是使用转换流 https://nodejs.org/api/stream.html#stream_class_stream_transform
const kafka = require('kafka-node') const options = { kafkaHost: '127.0.0.1:9092', groupId: 'Group' }; const consumerGroupStream = new kafka.ConsumerGroupStream(options, ['queue']); async function asyncFunction(message) { console.log('Message: ', message); } const Transform = require('stream').Transform const messageTransform = new Transform({ objectMode: true, decodeStrings: true, transform (message, encoding, done) { asyncFunction(message).then(() => { done() }) } }) consumerGroupStream .pipe(messageTransform)