我在Node.js
中有一个模块,它重复从MongoDB中选择一个文档并对其进行处理。一份文件只应处理一次。我也想使用多个流程概念。我想在不同的处理器上运行相同的模块(进程),这些处理器是独立运行的。
问题是,可能存在两个不同工作人员挑选和处理同一文档的情况。多个进程如何知道某个特定文档是由其他工作者处理的,所以我不应该触及它。我的独立流程无法与之沟通。我不能使用一个父进程来处理多个进程并充当它们之间的桥梁。如何在Node.js中避免这种问题?
答案 0 :(得分:2)
一种方法是为每个MongoDB文档分配一个唯一的数字ID,并为每个node.js工作者分配一个唯一的数字标识符。
例如,有一个名为NUM_WORKERS的env var,然后在你的node.js模块中:
var NumWorkers = process.env.NUM_WORKERS || 1;
然后,您需要为每个工作人员分配一个唯一的,连续的实例编号id(范围为0到NumWorkers-1)(例如,通过node.js进程初始化时读取的命令行参数)。您可以将其存储在名为MyWorkerInstanceNum的变量中。
当您从MongoDB中选择文档时,请调用以下函数(将文档的唯一documentId作为参数传递):
function isMine(documentId){
//
// Example: documentId=10
// NumWorkers= 4
// (10 % 4) = 2
// If MyWorkerInstanceNum is 2, return true, else return false.
return ((documentId % NumWorkers) === MyWorkerInstanceNum);
}
如果isMine()返回true,则仅继续实际处理文档。 因此,多个工人可能会选择"一个文档,但只有一个工人会实际处理它。
答案 1 :(得分:1)
只需通过其唯一ID保留正在处理的文档的事务日志。在已处理文档的事务日志表中,将状态写为以下之一(例如):
requested
initiated
processed
failed
您可能还希望该表中的列为stderr / stdout,以防您想知道失败或成功的原因,以及时间戳 - 这类事情。
在Node应用程序中初始化文档处理时,请按ID查找文档并检查其状态。如果它不存在,那么你可以自由地处理它。
伪代码(对不起,我不是蒙古人!):
db.collection.list('collectionName', function(err, doc) {
db.collection.find(doc.id, 'transactions', function(err, trx) {
if (trx === undefined || trx.status === 'failed') {
DocProcessor.child.process(doc)
} else {
// don't need to process it, it's already been done
}
})
})
您还需要在事务日志集合上启用并发锁定,以确保无法复制行(和后续作业)。如果这成为确保文档正确排队的挑战,请考虑添加AMQP服务来处理文档的排队。设置处理程序以管理子进程和事务日志记录的分发。流程将类似于:
MQ⇢日志⇢处理程序⇢Doc处理器子项