javascript - Meteor 中的延迟状态检查

标签 javascript mongodb design-patterns meteor

延迟状态检查

tl;dr - 当某个 Action 在指定的持续时间内没有发生时,有哪些好的设计模式可以使用react?


问题设置

我正在制作类似 Farmville 的应用程序。在此应用程序中,用户拥有他们照料的花园。每个花园都会跟踪一些变量——湿度、温度、酸碱度、硝酸盐等。该应用程序会指导您照料花园,为您创建任务。根据您提交的读数,它会通知您这些变量中的任何一个是否太低或太高。此外,如果您在指定的时间内没有读取变量,它会提醒您读取变量。

花园数据长这样

// garden object
{
  name: "Home garden",
  variables: {
    nitrate: {
      currentValue: 1.7,
      lastMeasuredAt: // some Date
    },
    nitrite: {
      currentValue: 0.5,
      lastMeasuredAt: // some Date
    }
  }
}

假设有一个名为“添加肥料”的任务。此任务的触发器是硝酸盐低于 2.5ppm 的条件。假设任务数据看起来像

// task object
{
  name: "Add fertilizer",
  instructions: "Open bag, dump on garden",
  condition: {
    variable: "nitrate",
    operator: "$lt",
    threshold: 2.5
  }
}

我使用 condition 数据构建了一个搜索查询,并查询花园以查看是否有匹配该条件的。我正在使用 MongoDB,因此可以使用普通的旧 Javascript 对象和 Meteor 来形成该查询,因此我有一个实时更新游标。

query = { variables.nitrate.currentValue: { $lt : 2.5 }};
Gardens.find(query).observe({
  added: function( garden ) {
    // add the task to the garden's task list
  },
  removed: function( garden ) {
    // remove the task from the garden's task list
  }
});

问题

好消息,这个模式适用于我描述的任务。但是,当任务基于已经过去的持续时间时呢?

// time-based task object
{
  name: "Take a nitrate reading",
  instructions: "Insert the nitrate probe",
  condition: {
    variable: "nitrate",
    operator: "$lt",
    interval: 2880 // 2 days in minutes
  }
}

我看到这是一个时间任务,因为它有一个 interval 而不是 threshold 并进行查询......

// using moment.js
expiration = moment().subtract(interval, 'minutes').toDate();
// find when lastMeasuredAt + interval < Now
query = { variables.nitrate.lastMeasuredAt: { $gt: expiration }};
Gardens.find(query).observe({
  added: function( garden ) {
    // add the task to the garden's task list
  },
  removed: function( garden ) {
    // remove the task from the garden's task list
  }
});

但这需要在将来的某个时候检查,而不是现在。这使我想到了问题的症结所在。检查到期时间的好方法是什么?

问题

有什么方法可以被动地做到这一点吗?

Meteor 的 Tracker 只支持在客户端工作,但是 peerlibrary:server-autorun确实在服务器上启用它。我可以使 Date 成为 react 性数据源,每隔几分钟左右更新一次,并将其包装在 Tracker.autorun 中。

这通常是通过某种作业队列来处理的吗?

如果使用作业队列实现,当将来提交新的读数将过期日期后移时,是更新现有作业还是删除旧作业并创建新作业更好?

最佳答案

有什么方法可以被动地做到这一点吗?

这通常是通过某种作业队列来处理的吗?

我最推荐的模式是定期检查某种作业队列中是否存在“过期”事件。

至于 react 性——它并不是在所有情况下都能正常工作。有比基于定时器的依赖失效更有效的结构。

下面的代码,你可以用来驱动一个基于 react 的定时器系统,甚至是一个支持收集的定时器系统。

如果您觉得这个答案不太准确,请发表评论,以便我改进。

// executes it's tasks regularly.
// up to the tasks system to implement "enqueue" & "execute"
ScheduledExecutor = (function() {

  function ScheduledExecutor(tasks, checkInterval) {
    this.tasks = tasks;
    this.checkInterval = checkInterval;
    this.running = false;
    this.timer = null;
    this.tick = _.bind(this.tick, this);
  }

  _.extend(ScheduledExecutor.prototype, {
    enqueue: function(task){
      this.tasks.enqueue(task);
    },
    tick: function(){
      this.tasks.execute();
      if (this.running) {
        this.timer = Meteor.setTimeout(this, this.checkInterval);
      }
    },
    start: function(){
      if (!this.running){
        this.running = true;
        this.tick();
      }
    },
    stop: function(){
      this.running = false;
      Meteor.clearTimeout(this.timer);
      this.timer = null;
    }
  });
  return ScheduledExecutor;
})();

// example of "reactive" task list.
//  finds due dependencies, and invalidates them
ReactiveTasks = (function(){
  function ReactiveTasks(){
    this.taskList = [];
  }

  _.extend(ReactiveTasks.prototype, {
    execute: function(){
      var now = Date.now();
      _.findWhere(this.taskList, function(task){
        return task.due <= now;
      }).forEach(function(task){
        task.dep.changed()
      });
      this.taskList = _.filter(this.taskList, function(task){
        return task.due > now;
      });
    },
    enqueue: function(due){
      var dep = new Tracker.Dependency;
      dep.depend();
      this.taskList.push({
        due: due,
        dep: dep
      });
    }
  });
  return ReactiveTasks;
})();

// executes tasks backed by a collection
//  finds "due" tasks, then calls the "executor"
//  the executor should interpret the task, and 
/// call the correct library function
CollectionTasks = (function(){
  function CollectionTasks(collection, executor){
    this.collection = collection;
    this.executor = executor;
  }
  _.extend(CollectionTasks.prototype, {
    execute: function(){
      var self = this, 
        now = Date.now();
      self.collection.find({
        due: {
          $lte: now
        }
      }).forEach(function(task){
        self.collection.remove({_id: task._id});
        self.executor.execute(task);
      });
    },
    enqueue: function(task){
      this.collection.insert(task);
    }
  });
  return CollectionTasks;
})();

关于javascript - Meteor 中的延迟状态检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28283963/

相关文章:

javascript - 数字和字符串全局对象的用途?

java - 如何以干净的方式对越来越多的带有参数的命令进行建模

javascript - 循环选择列表菜单以创建搜索过滤器

node.js - MongoDB:用字典更新数组中的文档

node.js - Mongoose:分配类型为 'array of Strings' 的字段

mongodb - mLab 连接错误 : Database name cannot have reserved characters for mongodb://

java - 必须有更好的方法来编码这个 :(

asp.net - ASP.NET MVC 中的 NHibernate 事务管理 - 应该如何完成?

用于 javascript 和 css 的 PHP 内容缓存

javascript - 发布版本中未调用 Webview Javascript 方法