Meteor Status Check Delay

Checking Delayed Status

tl; dr - What are good design patterns for responding when an action has not been completed for a certain duration?


Problem setting

I am making an application similar to farmerville. In this application, users have gardens that they care about. There are several variables that are tracked in each garden - humidity, temperature, ph, nitrate, etc. The application directs you to the care of the garden, creating tasks for you. It informs you if any of these variables is too low or too high based on the readings you sent. In addition, it reminds you to take a reading for a variable if you have not taken it for a certain period of time.

Garden data look like

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

, , " ". - , 2,5 ppm. ,

// 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 task list
  },
  removed: function( garden ) {
    // remove the task from the garden 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 task list
  },
  removed: function( garden ) {
    // remove the task from the garden task list
  }
});

- , . . , ?

?

Meteor Tracker , peerlibrary:server-autorun . , - , Tracker.autorun.

- ?

, , , ?

+4
1

?

- ?

- "" .

- . , .

, , .

, , , .

// executes it 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;
})();
+2

All Articles