如何避免cursor.observe上的竞争条件?

时间:2012-11-08 21:06:15

标签: meteor

种族歧视

在我的Meteor应用程序中,我在observe内创建了publish,在某些条件下插入了一些新数据。关键是有时候我们有重复的订阅,竞争条件会导致我们复制插入的数据。 如果是not possible to have "singleton observers"

  • 我们如何避免竞争条件和数据库中重复插入的数据?

示例:

Meteor.publish("fortuneUpdate", function () {
  var selector = {user: this.userId, seen:false};

  DailyFortunes.find(selector).observe({
    removed: function(doc, beforeIndex){
      if(DailyFortunes.find(selector).count()<1)
        createDailyFortune(this.userId);
    }
  });

}

此问题已从How cursor.observe works and how to avoid multiple instances running?

移至

2 个答案:

答案 0 :(得分:2)

According to Tom,目前不可能确保共享具有相同参数的订阅调用。 所以,如果你遇到了同样的问题,在观察者中创建了多余的数据,我建议你作为解决方法:

  1. 创建健壮 indexes,以防止重复创建数据。 Compound Keys很可能是你需要的。
  2. 忽略竞争条件,处理观察者内部的重复键错误异常。
  3. 示例

    Collection.find(selector).observe({
      removed: function(document){
          try {
            // Workaround to avoid race conditions > https://stackoverflow.com/q/13095647/599991
            createNewDocument();
          } catch (e) {
            // XXX string parsing sucks, maybe
            // https://jira.mongodb.org/browse/SERVER-3069 will get fixed one day
            if (e.name !== 'MongoError') throw e;
              var match = e.err.match(/^E11000 duplicate key error index: ([^ ]+)/);
            if (!match) throw e;
            //if match, just do nothing.
          }
        self.flush();
      }
    });
    

答案 1 :(得分:2)

这是一种奇怪的模式。你能分享一些示例代码吗?

一般来说,我或者期望在方法中看到突变,或者在服务器上设置observe Meteor.startup()。 (如果您运行多个服务器进程,后者是棘手的,但在多进程机制中还有很多其他事情。我们将有更好的模式。)

因为它可以是任意JS,所以每个订阅客户端必须运行一次发布函数。它可以记录新订阅,设置每个客户端服务器状态,或根据this.userId或甚至随机源改变其行为。例如,考虑一个订阅,它将从DB集合中随机选择的10个文档返回给每个订阅的客户端!

因此,优化订阅相同数据集的许多客户的情况的地方是在DB查询层:如果一千个客户订阅了相同的数据库查询,我们将只运行一次基础查询。