这就是初始化我的消费者的方式:
const client = new kafka.Client(config.ZK_HOST)
const consumer = new kafka.Consumer(client, [{ topic: config.KAFKA_TOPIC, offset: 0}],
{
autoCommit: false
})
现在,消费者consumer.on('message', message => applyMessage(message))
问题是applyMessage
使用knex
与数据库进行对话,代码类似于:
async function applyMessage(message: kafka.Message) {
const usersCount = await db('users').count()
// just assume we ABSOLUTELY need to calculate a number of users,
// so we need previous state
await db('users').insert(inferUserFromMessage(message))
}
上面的代码使applyMessage
对kafka中的所有消息并行执行,因此在上面的代码中,假设数据库中还没有用户,usersCount
始终将为0自第一次调用applyMessage
以来,kafka发出的第二条消息应为1,这已插入一个用户。
如何以所有applyMessage
函数顺序运行的方式“同步”代码?
答案 0 :(得分:1)
您需要实现某种互斥体。基本上,是一个将事物排队等待同步执行的类。例子
var Mutex = function() {
this.queue = [];
this.locked = false;
};
Mutex.prototype.enqueue = function(task) {
this.queue.push(task);
if (!this.locked) {
this.dequeue();
}
};
Mutex.prototype.dequeue = function() {
this.locked = true;
const task = this.queue.shift();
if (task) {
this.execute(task);
} else {
this.locked = false;
}
};
Mutex.prototype.execute = async function(task) {
try { await task(); } catch (err) { }
this.dequeue();
}
为了使其正常工作,您的applyMessage
函数(无论是处理Kafka消息的函数)都需要返回Promise
-注意异步也已从父函数移到了返回的Promise函数:< / p>
function applyMessage(message: kafka.Message) {
return new Promise(async function(resolve,reject) {
try {
const usersCount = await db('users').count()
// just assume we ABSOLUTELY need to calculate a number of users,
// so we need previous state
await db('users').insert(inferUserFromMessage(message))
resolve();
} catch (err) {
reject(err);
}
});
}
最后,每次applyMessage
的调用都需要添加到Mutex队列中,而不是直接调用:
var mutex = new Mutex();
consumer.on('message', message => mutex.enqueue(function() { return applyMessage(message); }))