public function getTimestamp() { $ts = null; if ($this->tsDate !== null) { $ts = $this->tsDate; } if ($this->isTimeAvailable && $this->tsTime !== null) { $ts += $this->tsTime - HDate::getTimestampOnBeginning((int) $this->tsTime, HDate::BEGINNING_DAY); } return $ts; }
private function parseTimestamp() { $date = ''; $op = ''; if (preg_match('/^(?:\\s*(<>|<=|>=|<|>|=))?(.*)$/', $this->value, $matches)) { $date = $matches[2]; $op = $matches[1]; } else { $date = $this->value; } $parsePattern = ''; if (preg_match('/^\\d{2}.\\d{2}.\\d{2}$/', $date)) { $parsePattern = 'dd.MM.yy'; } elseif (preg_match('/^\\d{2}.\\d{2}.\\d{2} \\d{2}:\\d{2}$/', $date)) { $parsePattern = 'dd.MM.yy HH:mm'; } elseif (preg_match('/^\\d{2}.\\d{2}.\\d{2} \\d{2}:\\d{2}:\\d{2}$/', $date)) { $parsePattern = 'dd.MM.yy HH:mm:ss'; } if (($tsBegin = CDateTimeParser::parse($date, $parsePattern)) === false) { return false; } $this->_tsBeginValue = $tsBegin; $beginDay = HDate::getTimestampOnBeginning($tsBegin, HDate::BEGINNING_DAY); $endDay = $beginDay + 86399; if ($tsBegin == $beginDay) { //если выбрали день (без времени) if (empty($op) || $op == '=') { $this->_tsEndValue = $endDay; //до конца дня } elseif ($op == '>' || $op == '<=') { $this->_tsBeginValue = $endDay; } } $this->_tsOperator = $op; return true; }
public function actionIndex($args = array()) { Yii::app()->db->createCommand('SET AUTOCOMMIT=0')->execute(); $this->checkLongExecuted(); //READ COMMITTED отличается от изоляции по умолчанию (REPEATABLE READ), тем, //что в REPEATABLE READ второй селект вернёт данные те же что и в первом (не смотря на то, //что данные были закоммичены первой транзакцией ), //т.е. у REPEATABLE READ полная согласованноть чтения данных $this->setIsolationLevel('READ COMMITTED'); $candidateCriteria = new CDbCriteria(array('order' => 't.priority DESC, RAND()')); $db = Yii::app()->db; $c = 0; $time = time(); while (1) { $transaction = $db->beginTransaction(); try { $curJob = Job::model()->resetScope()->available(self::MAX_COUNT_FAILURES, $time)->find($candidateCriteria); //Нет задач, выходим if ($curJob === null) { break; } } catch (CDbException $e) { //Если запись залочена другой транзакцией, то пропускаем if ($e->getCode() == self::ERROR_CODE_LOCK_WAIT_TIMEOUT) { $transaction->rollback(); $candidateCriteria->addCondition('t.id_job != ' . $curJob->id_job); continue; } throw $e; } //Если время выполнения задачи еще не подошло, то пропускаем if (!$curJob->getExecutionTimeHasCome($time)) { $transaction->rollback(); continue; } //Если достигли максимального количества ошибок, исключаем эту задачу if ($curJob->failures == self::MAX_COUNT_FAILURES) { $transaction->rollback(); $candidateCriteria->addCondition('t.id_job != ' . $curJob->id_job); $this->log($curJob->name, $curJob->failures); continue; } elseif ($curJob->failures == 1) { $this->log($curJob->name, $curJob->failures); } //Увеличиваем счетчик ошибок и сохраняем //для того чтобы, если скрипт задачи упадет, //то при следующем запуске планировщика мы об этом узнаем /*if ($curJob->is_null_start_date) { $curJob->start_date = null; } else { $curJob->start_date = time(); }*/ $curJob->failures++; $curJob->save(false); $transaction->commit(); $this->setIsolationLevel('REPEATABLE READ'); //Создаем и запускаем задачу $schedulerJob = $this->createJob($curJob); if (!$schedulerJob instanceof SchedulerJob) { throw new ErrorException('Класс задачи ' . $curJob->name . ' ' . get_class($schedulerJob) . ' должен расширять класс SchedulerJob.'); } $result = (int) $schedulerJob->run(); $this->setIsolationLevel('READ COMMITTED'); $interval = $curJob->interval_value; //Если вернулся код ошибки if ($result !== SchedulerJob::RESULT_OK) { $interval = $curJob->error_repeat_interval; } else { $curJob->failures = 0; } $curJob->last_start_date = $curJob->next_start_date; $curJob->next_start_date += $interval; if ($curJob->next_start_date < $time) { $newDate = HDate::getTimestampOnBeginning($time, HDate::BEGINNING_DAY); $timeParts = getdate($curJob->next_start_date); $newDate += $timeParts['hours'] * 3600 + $timeParts['minutes'] * 60 + $timeParts['seconds']; if ($newDate - $interval > $time) { $step = floor(($newDate - $time) / $interval); $newDate = $newDate - $step * $interval; } if ($newDate < $time) { $step = floor(($time - $newDate) / $interval) + 1; $newDate = $newDate + $step * $interval; } $curJob->last_start_date = $time; $curJob->next_start_date = $newDate; } //сохраняем задачу $transaction = $db->beginTransaction(); if (empty($curJob->first_start_date)) { $curJob->first_start_date = $curJob->last_start_date; } $curJob->start_date = null; $curJob->save(false); $transaction->commit(); } }