/**
  * 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;
 }