def _read_next_failed_past_due_task(self):
        min_fail_end_date = date_minus_seconds(date_now(), MAX_FAIL_DUE_TIME)
        q = { "state": STATE_FAILED,
              "engineGuid": self._engine.engine_guid,
              "$or": [
                      {
                      "plan.nextOccurrence": {"$lte": date_now()}
                  },

                      {
                      "plan": {"$exists": False},
                      "reschedulable": False,
                      "endDate": {"$lte": min_fail_end_date}
                  }


              ]
        }

        msg = "Task failed and is past due. Cancelling..."
        log_entry = state_change_log_entry(STATE_CANCELED, message=msg)
        u = {"$set" : { "state" : STATE_CANCELED},
             "$push": {
                 "logs": log_entry.to_document()
             }
        }

        return self._task_collection.find_and_modify(query=q, update=u,
                                                     new=True)
    def _read_next_failed_past_due_task(self):
        min_fail_end_date = date_minus_seconds(date_now(), MAX_FAIL_DUE_TIME)
        q = {
            "$or": [
                {
                    "state": State.FAILED,
                    "engineGuid": self._engine.engine_guid,
                    "nextRetryDate": None,
                    "finalRetryDate": {"$lte": date_now()},
                    "plan.nextOccurrence": {"$lte": date_now()}
                },
                {
                    "state": State.FAILED,
                    "engineGuid": self._engine.engine_guid,
                    "plan": {"$exists": False},
                    "nextRetryDate": None,
                    "finalRetryDate": {"$lte": min_fail_end_date}
                }
            ]
        }

        msg = "Task failed and is past due. Cancelling..."
        log_entry = state_change_log_entry(State.CANCELED, message=msg)
        u = {"$set" : { "state" : State.CANCELED},
             "$push": {
                 "logs": log_entry.to_document()
             }
        }

        task = self.task_collection.find_one(query=q)
        if task:
            return self.task_collection.find_and_modify(query=q, update=u, new=True)
    def read_next_task(self):

        log_entry = state_change_log_entry(STATE_IN_PROGRESS)
        q = self._get_scheduled_tasks_query()
        u = {
            "$set": {
                "state": STATE_IN_PROGRESS,
                "engineGuid": self._engine.engine_guid
            },
            "$push": {
                "logs": log_entry.to_document()
            }
        }

        # sort by priority except every third tick, we sort by created date to
        # avoid starvation
        if self._tick_count % 5 == 0:
            s = [("createdDate", 1)]
        else:
            s = [("priority", 1)]

        c = self._task_collection

        task = c.find_and_modify(query=q, sort=s, update=u, new=True)

        return task
    def read_next_task(self):

        log_entry = state_change_log_entry(STATE_IN_PROGRESS)
        q = self._get_scheduled_tasks_query()
        u = {"$set" : { "state" : STATE_IN_PROGRESS,
                        "engineGuid": self._engine.engine_guid},
             "$push": {"logs":log_entry.to_document()}}

        # sort by priority except every third tick, we sort by created date to
        # avoid starvation
        if self._tick_count % 5 == 0:
            s = [("createdDate", 1)]
        else:
            s = [("priority", 1)]

        c = self._task_collection

        task = c.find_and_modify(query=q, sort=s, update=u, new=True)

        return task
    def read_next_task(self):

        log_entry = state_change_log_entry(State.IN_PROGRESS)
        q = self._get_scheduled_tasks_query()
        u = {
            "$set": {
                "state": State.IN_PROGRESS,
                "engineGuid": self._engine.engine_guid
            },
            "$push": {
                "logs": log_entry.to_document()
            }
        }

        # Ensure that engines will not pickup tasks that were already processed by other engines
        if self._tick_count % 2 == 0:
            q["engineGuid"] = self._engine.engine_guid
        else:
            q["engineGuid"] = None

        # sort by priority except every third tick, we sort by created date to
        # avoid starvation
        if self._tick_count % 5 == 0:
            s = [("createdDate", 1)]
        else:
            s = [("priority", 1)]

        c = self.task_collection

        task = c.find_one(query=q, sort=s)
        if task:
            if task.engine_guid and task.engine_guid != self._engine.engine_guid:
                raise Exception("Unexpected error")
            else:
                task = c.find_and_modify(query=q, sort=s, update=u, new=True)

        return task