node.js 异步迭代时的数据一致性

node.js data consistency when iterating asynchronously

我有一个工具,基本思路如下:

//get a bunch of couchdb databases. this is an array
    const jsonFile = require('jsonfile');
    let dbList = getDbList();
    const filePath = 'some/path/to/file';
    const changesObject = {};


     //iterate the db list. do asynchronous stuff on each iteration
     dbList.forEach(function(db){
        let merchantDb = nano.use(db);

        //get some changes from the database. validate inside callback 
        merchantDb.get("_changes", function(err,changes){
          validateChanges(changes);
          changesObject['db'] = changes.someAttribute;
          //write changes to file
          jsonFile.writeFile(filePath, changesObject, function (err) {
            if (err) {
              logger.error("Unable to write to file: ");
            }
          });
    })

const validateChanges = function(changes) {
 if (!validateLogic(changes) sendAlertMail();
}

为了提高性能,迭代不是同步完成的。因此在'parallel'中可以有多次迭代运行。我的问题是这会导致任何数据不一致 and/or 文件写入过程有任何问题吗?

编辑: 每次迭代都会写入相同的文件。

编辑:2 更改存储为具有键值对的 JSON 对象。关键是数据库名称。

如果你真的在写一个 单个 文件,你看起来是(虽然很难确定),那么不;你有一个竞争条件,其中多个回调可能会同时尝试写入同一个文件(请记住,I/O 不会在 Node 中的 JavaScript 线程上完成,除非你使用 *Sync 函数),这最多意味着最后一个获胜,最坏的情况下意味着 I/O 由于重叠而导致的错误。

如果您要为每个 db 编写单独的文件,那么前提是 validateChangesvalidateLogicsendAlertMail 之间没有串扰(共享状态)等应该没问题

仅供参考:它将启动任务(作业)获取更改,然后将其写出;对 get 的调用的回调将不会是 运行 直到稍后所有这些作业都排队时。

您正在循环中创建闭包,但您这样做的方式没问题,因为您是在 forEach 回调中进行的,而且您没有使用 dbget 回调中(对于 forEach 回调会很好,但对于您可能循环数组的其他一些方式则不行)。如果您有兴趣,请在 this question's answers 中查看有关这方面的详细信息。

但这条线是可疑的:

let merchantDb = nano.use('db');

我怀疑你的意思是(没有引号):

let merchantDb = nano.use(db);

对于它的价值,从问题的更新和您的各种评论来看,更好的解决方案是 而不是 每次单独写出文件。相反,您想收集更改然后将它们写出来。

您可以像这样使用您正在使用的经典节点回调 API 来做到这一点:

let completed = 0;
//iterate the db list. do asynchronous stuff on each iteration
dbList.forEach(function(db) {
    let merchantDb = nano.use(db);

    //get some changes from the database. validate inside callback 
    merchantDb.get("_changes", function(err, changes) {
        if (err) {
            // Deal with the fact there was an error (don't return)
        } else {
            validateChanges(changes);
            changesObject[db] = changes.someAttribute; // <=== NOTE: This line had 'db' rather than db, I assume that was meant to be just db
        }
        if (++completed === dbList.length) {
            // All done, write changes to file
            jsonFile.writeFile(filePath, changesObject, function(err) {
                if (err) {
                    logger.error("Unable to write to file: ");
                }
            });
        }
    })
});