2011-03-10 13:48:29 -08:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/*
|
2012-03-13 16:21:04 -07:00
|
|
|
* Copyright 2012 Facebook, Inc.
|
2011-03-10 13:48:29 -08:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2012-03-13 16:21:04 -07:00
|
|
|
final class PhabricatorTaskmasterDaemon extends PhabricatorDaemon {
|
2011-03-10 13:48:29 -08:00
|
|
|
|
|
|
|
public function run() {
|
|
|
|
$lease_ownership_name = $this->getLeaseOwnershipName();
|
|
|
|
|
2012-10-31 15:22:16 -07:00
|
|
|
$task_table = new PhabricatorWorkerActiveTask();
|
2011-03-10 13:48:29 -08:00
|
|
|
$taskdata_table = new PhabricatorWorkerTaskData();
|
|
|
|
|
|
|
|
$sleep = 0;
|
|
|
|
do {
|
2012-10-31 15:22:16 -07:00
|
|
|
$this->log('Dequeuing a task...');
|
|
|
|
|
2011-03-10 13:48:29 -08:00
|
|
|
$conn_w = $task_table->establishConnection('w');
|
|
|
|
queryfx(
|
|
|
|
$conn_w,
|
|
|
|
'UPDATE %T SET leaseOwner = %s, leaseExpires = UNIX_TIMESTAMP() + 15
|
2011-03-11 09:34:22 -08:00
|
|
|
WHERE leaseOwner IS NULL LIMIT 1',
|
2011-03-10 13:48:29 -08:00
|
|
|
$task_table->getTableName(),
|
|
|
|
$lease_ownership_name);
|
|
|
|
$rows = $conn_w->getAffectedRows();
|
|
|
|
|
2011-03-11 09:34:22 -08:00
|
|
|
if (!$rows) {
|
2012-10-31 15:22:16 -07:00
|
|
|
$this->log('No unleased tasks. Dequeuing an expired lease...');
|
2012-06-11 16:22:08 -07:00
|
|
|
queryfx(
|
2011-03-11 09:34:22 -08:00
|
|
|
$conn_w,
|
|
|
|
'UPDATE %T SET leaseOwner = %s, leaseExpires = UNIX_TIMESTAMP() + 15
|
|
|
|
WHERE leaseExpires < UNIX_TIMESTAMP() LIMIT 1',
|
2012-06-11 16:22:08 -07:00
|
|
|
$task_table->getTableName(),
|
|
|
|
$lease_ownership_name);
|
2011-03-11 09:34:22 -08:00
|
|
|
$rows = $conn_w->getAffectedRows();
|
|
|
|
}
|
|
|
|
|
2011-03-10 13:48:29 -08:00
|
|
|
if ($rows) {
|
|
|
|
$data = queryfx_all(
|
|
|
|
$conn_w,
|
|
|
|
'SELECT task.*, taskdata.data _taskData, UNIX_TIMESTAMP() _serverTime
|
|
|
|
FROM %T task LEFT JOIN %T taskdata
|
2011-04-14 12:07:57 -07:00
|
|
|
ON taskdata.id = task.dataID
|
2011-03-10 13:48:29 -08:00
|
|
|
WHERE leaseOwner = %s AND leaseExpires > UNIX_TIMESTAMP()
|
|
|
|
LIMIT 1',
|
|
|
|
$task_table->getTableName(),
|
|
|
|
$taskdata_table->getTableName(),
|
|
|
|
$lease_ownership_name);
|
|
|
|
$tasks = $task_table->loadAllFromArray($data);
|
|
|
|
$tasks = mpull($tasks, null, 'getID');
|
|
|
|
|
|
|
|
$task_data = array();
|
|
|
|
foreach ($data as $row) {
|
|
|
|
$tasks[$row['id']]->setServerTime($row['_serverTime']);
|
|
|
|
if ($row['_taskData']) {
|
|
|
|
$task_data[$row['id']] = json_decode($row['_taskData'], true);
|
|
|
|
} else {
|
|
|
|
$task_data[$row['id']] = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($tasks as $task) {
|
2012-10-31 15:22:16 -07:00
|
|
|
$id = $task->getID();
|
|
|
|
$class = $task->getTaskClass();
|
|
|
|
|
|
|
|
$this->log("Working on task {$id} ({$class})...");
|
|
|
|
|
2011-03-10 13:48:29 -08:00
|
|
|
// TODO: We should detect if we acquired a task with an expired lease
|
|
|
|
// and log about it / bump up failure count.
|
|
|
|
|
|
|
|
// TODO: We should detect if we acquired a task with an excessive
|
|
|
|
// failure count and fail it permanently.
|
|
|
|
|
|
|
|
$data = idx($task_data, $task->getID());
|
|
|
|
try {
|
2012-05-30 16:38:53 -07:00
|
|
|
if (!class_exists($class) ||
|
|
|
|
!is_subclass_of($class, 'PhabricatorWorker')) {
|
2011-03-10 13:48:29 -08:00
|
|
|
throw new Exception(
|
|
|
|
"Task class '{$class}' does not extend PhabricatorWorker.");
|
|
|
|
}
|
|
|
|
$worker = newv($class, array($data));
|
|
|
|
|
|
|
|
$lease = $worker->getRequiredLeaseTime();
|
|
|
|
if ($lease !== null) {
|
|
|
|
$task->setLeaseDuration($lease);
|
|
|
|
}
|
|
|
|
|
2012-10-31 15:22:16 -07:00
|
|
|
$t_start = microtime(true);
|
2011-03-10 13:48:29 -08:00
|
|
|
$worker->executeTask();
|
2012-10-31 15:22:16 -07:00
|
|
|
$t_end = microtime(true);
|
2011-03-10 13:48:29 -08:00
|
|
|
|
2012-10-31 15:22:16 -07:00
|
|
|
$task->archiveTask(
|
|
|
|
PhabricatorWorkerArchiveTask::RESULT_SUCCESS,
|
|
|
|
(int)(1000000 * ($t_end - $t_start)));
|
|
|
|
$this->log("Task {$id} complete! Moved to archive.");
|
2011-03-10 13:48:29 -08:00
|
|
|
} catch (Exception $ex) {
|
|
|
|
$task->setFailureCount($task->getFailureCount() + 1);
|
|
|
|
$task->save();
|
2012-10-31 15:22:16 -07:00
|
|
|
|
|
|
|
$this->log("Task {$id} failed!");
|
2011-03-10 13:48:29 -08:00
|
|
|
throw $ex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$sleep = 0;
|
|
|
|
} else {
|
|
|
|
$sleep = min($sleep + 1, 30);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->sleep($sleep);
|
|
|
|
} while (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function getLeaseOwnershipName() {
|
|
|
|
static $name = null;
|
|
|
|
if ($name === null) {
|
|
|
|
$name = getmypid().':'.time().':'.php_uname('n');
|
|
|
|
}
|
|
|
|
return $name;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|