/** * Run scheduled event triggers which are due for execution. * * @return void */ private function executeTriggers() { // We run only a limited number of triggers before ending the execution // phase. If we ran until exhaustion, we could end up executing very // out-of-date triggers if there was a long backlog: trigger changes // during this phase are not reflected in the event table until we run // another scheduling phase. // If we exit this phase with triggers still ready to execute we'll // jump back into the scheduling phase immediately, so this just makes // sure we don't spend an unreasonably long amount of time without // processing trigger updates and doing rescheduling. $limit = 100; $now = PhabricatorTime::getNow(); $triggers = id(new PhabricatorWorkerTriggerQuery())->setViewer($this->getViewer())->setOrder(PhabricatorWorkerTriggerQuery::ORDER_EXECUTION)->withNextEventBetween(null, $now)->needEvents(true)->setLimit($limit)->execute(); foreach ($triggers as $trigger) { $event = $trigger->getEvent(); // Execute the trigger action. $trigger->executeTrigger($event->getLastEventEpoch(), $event->getNextEventEpoch()); // Now that we've executed the trigger, the current trigger epoch is // going to become the last epoch. $last_epoch = $event->getNextEventEpoch(); // If this is a recurring trigger, give it an opportunity to reschedule. $reschedule_epoch = $trigger->getNextEventEpoch($last_epoch, $is_reschedule = true); // Don't reschedule events unless the next occurrence is in the future. if ($reschedule_epoch !== null && $last_epoch !== null && $reschedule_epoch <= $last_epoch) { throw new Exception(pht('Trigger is attempting to perform a routine reschedule where ' . 'the next event (at %s) does not occur after the previous event ' . '(at %s). Routine reschedules must strictly move event triggers ' . 'forward through time to avoid executing a trigger an infinite ' . 'number of times instantaneously.', $reschedule_epoch, $last_epoch)); } $new_event = PhabricatorWorkerTriggerEvent::initializeNewEvent($trigger)->setLastEventEpoch($last_epoch)->setNextEventEpoch($reschedule_epoch); $event->openTransaction(); // Remove the event we just processed. $event->delete(); // See note in the scheduling phase about this; we save the new event // even if the next epoch is `null`. $new_event->save(); $event->saveTransaction(); } }
public static function initializeNewEvent(PhabricatorWorkerTrigger $trigger) { $event = new PhabricatorWorkerTriggerEvent(); $event->setTriggerID($trigger->getID()); return $event; }