public function processRequest() { $logs = id(new PhabricatorDaemonLog())->loadAllWhere('`status` != %s ORDER BY id DESC LIMIT 15', 'exit'); $request = $this->getRequest(); $user = $request->getUser(); $daemon_table = new PhabricatorDaemonLogListView(); $daemon_table->setUser($user); $daemon_table->setDaemonLogs($logs); $daemon_panel = new AphrontPanelView(); $daemon_panel->setHeader('Recently Launched Daemons'); $daemon_panel->appendChild($daemon_table); $tasks = id(new PhabricatorWorkerTask())->loadAllWhere('leaseOwner IS NOT NULL'); $rows = array(); foreach ($tasks as $task) { $rows[] = array($task->getID(), $task->getTaskClass(), $task->getLeaseOwner(), $task->getLeaseExpires() - time(), $task->getFailureCount(), phutil_render_tag('a', array('href' => '/daemon/task/' . $task->getID() . '/', 'class' => 'button small grey'), 'View Task')); } $leased_table = new AphrontTableView($rows); $leased_table->setHeaders(array('ID', 'Class', 'Owner', 'Expires', 'Failures', '')); $leased_table->setColumnClasses(array('n', 'wide', '', '', 'n', 'action')); $leased_table->setNoDataString('No tasks are leased by workers.'); $leased_panel = new AphrontPanelView(); $leased_panel->setHeader('Leased Tasks'); $leased_panel->appendChild($leased_table); $task_table = new PhabricatorWorkerTask(); $queued = queryfx_all($task_table->establishConnection('r'), 'SELECT taskClass, count(*) N FROM %T GROUP BY taskClass ORDER BY N DESC', $task_table->getTableName()); $rows = array(); foreach ($queued as $row) { $rows[] = array(phutil_escape_html($row['taskClass']), number_format($row['N'])); } $queued_table = new AphrontTableView($rows); $queued_table->setHeaders(array('Class', 'Count')); $queued_table->setColumnClasses(array('wide', 'n')); $queued_table->setNoDataString('Task queue is empty.'); $queued_panel = new AphrontPanelView(); $queued_panel->setHeader('Queued Tasks'); $queued_panel->appendChild($queued_table); $cursors = id(new PhabricatorTimelineCursor())->loadAll(); $rows = array(); foreach ($cursors as $cursor) { $rows[] = array(phutil_escape_html($cursor->getName()), number_format($cursor->getPosition())); } $cursor_table = new AphrontTableView($rows); $cursor_table->setHeaders(array('Name', 'Position')); $cursor_table->setColumnClasses(array('wide', 'n')); $cursor_table->setNoDataString('No timeline cursors exist.'); $cursor_panel = new AphrontPanelView(); $cursor_panel->setHeader('Timeline Cursors'); $cursor_panel->appendChild($cursor_table); $nav = $this->buildSideNavView(); $nav->selectFilter(''); $nav->appendChild(array($daemon_panel, $cursor_panel, $queued_panel, $leased_panel)); return $this->buildApplicationPage($nav, array('title' => 'Console')); }
public function run() { $lease_ownership_name = $this->getLeaseOwnershipName(); $task_table = new PhabricatorWorkerTask(); $taskdata_table = new PhabricatorWorkerTaskData(); $sleep = 0; do { $conn_w = $task_table->establishConnection('w'); queryfx($conn_w, 'UPDATE %T SET leaseOwner = %s, leaseExpires = UNIX_TIMESTAMP() + 15 WHERE leaseOwner IS NULL LIMIT 1', $task_table->getTableName(), $lease_ownership_name); $rows = $conn_w->getAffectedRows(); if (!$rows) { $rows = queryfx($conn_w, 'UPDATE %T SET leaseOwner = %s, leaseExpires = UNIX_TIMESTAMP() + 15 WHERE leaseExpires < UNIX_TIMESTAMP() LIMIT 1', $task_table->getTableName(), $lease_ownership_name); $rows = $conn_w->getAffectedRows(); } if ($rows) { $data = queryfx_all($conn_w, 'SELECT task.*, taskdata.data _taskData, UNIX_TIMESTAMP() _serverTime FROM %T task LEFT JOIN %T taskdata ON taskdata.id = task.dataID 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) { // 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()); $class = $task->getTaskClass(); try { PhutilSymbolLoader::loadClass($class); if (!is_subclass_of($class, 'PhabricatorWorker')) { throw new Exception("Task class '{$class}' does not extend PhabricatorWorker."); } $worker = newv($class, array($data)); $lease = $worker->getRequiredLeaseTime(); if ($lease !== null) { $task->setLeaseDuration($lease); } $worker->executeTask(); $task->delete(); if ($data !== null) { queryfx($conn_w, 'DELETE FROM %T WHERE id = %d', $taskdata_table->getTableName(), $task->getDataID()); } } catch (Exception $ex) { $task->setFailureCount($task->getFailureCount() + 1); $task->save(); throw $ex; } } $sleep = 0; } else { $sleep = min($sleep + 1, 30); } $this->sleep($sleep); } while (true); }