diff --git a/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php b/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php --- a/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php +++ b/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php @@ -2,6 +2,17 @@ abstract class HarbormasterBuildStepImplementation { + private $associatedWorker; + + final public function setAssociatedWorker(PhabricatorWorker $worker) { + $this->associatedWorker = $worker; + return $this; + } + + final protected function stillWorking() { + $this->associatedWorker->stillWorking(); + } + public static function getImplementations() { return id(new PhutilSymbolLoader()) ->setAncestorClass('HarbormasterBuildStepImplementation') diff --git a/src/applications/harbormaster/step/HarbormasterCommandBuildStepImplementation.php b/src/applications/harbormaster/step/HarbormasterCommandBuildStepImplementation.php --- a/src/applications/harbormaster/step/HarbormasterCommandBuildStepImplementation.php +++ b/src/applications/harbormaster/step/HarbormasterCommandBuildStepImplementation.php @@ -78,8 +78,9 @@ foreach ($futures->setUpdateInterval(1) as $key => $future_iter) { if ($future_iter === null) { - // Check to see if we should abort. + // Flag as still working and check to see if we should abort. if ($build_update <= 0) { + $this->stillWorking(); $build->reload(); if ($this->shouldAbort($build, $build_target)) { $future->resolveKill(); diff --git a/src/applications/harbormaster/worker/HarbormasterTargetWorker.php b/src/applications/harbormaster/worker/HarbormasterTargetWorker.php --- a/src/applications/harbormaster/worker/HarbormasterTargetWorker.php +++ b/src/applications/harbormaster/worker/HarbormasterTargetWorker.php @@ -49,6 +49,7 @@ } $implementation = $target->getImplementation(); + $implementation->setAssociatedWorker($this); $implementation->execute($build, $target); $next_status = HarbormasterBuildTarget::STATUS_PASSED; diff --git a/src/infrastructure/daemon/workers/PhabricatorTaskmasterDaemon.php b/src/infrastructure/daemon/workers/PhabricatorTaskmasterDaemon.php --- a/src/infrastructure/daemon/workers/PhabricatorTaskmasterDaemon.php +++ b/src/infrastructure/daemon/workers/PhabricatorTaskmasterDaemon.php @@ -16,7 +16,7 @@ $this->log("Working on task {$id} ({$class})..."); - $task = $task->executeTask(); + $task = $task->executeTask($this); $ex = $task->getExecutionException(); if ($ex) { if ($ex instanceof PhabricatorWorkerPermanentFailureException) { diff --git a/src/infrastructure/daemon/workers/PhabricatorWorker.php b/src/infrastructure/daemon/workers/PhabricatorWorker.php --- a/src/infrastructure/daemon/workers/PhabricatorWorker.php +++ b/src/infrastructure/daemon/workers/PhabricatorWorker.php @@ -5,7 +5,9 @@ */ abstract class PhabricatorWorker { + private $daemon = null; private $data; + private $activeTask; private static $runAllTasksInProcess = false; private $queuedTasks = array(); @@ -18,6 +20,10 @@ const PRIORITY_BULK = 3000; const PRIORITY_IMPORT = 4000; + public function setDaemon(PhutilDaemon $daemon = null) { + $this->daemon = $daemon; + } + /* -( Configuring Retries and Failures )----------------------------------- */ @@ -79,7 +85,8 @@ abstract protected function doWork(); - final public function __construct($data) { + final public function __construct(PhabricatorWorkerTask $task, $data) { + $this->activeTask = $task; $this->data = $data; } @@ -110,7 +117,7 @@ if (self::$runAllTasksInProcess) { // Do the work in-process. - $worker = newv($task_class, array($data)); + $worker = $task->getWorkerInstance(); while (true) { try { @@ -147,6 +154,28 @@ } } + /** + * Mark the operation as still working. + */ + final public function stillWorking() { + // If we have less than 80% of our working time left, or less + // than 10 seconds (whichever is greater), extend it by the + // required lease time. + $time_left = + $this->activeTask->getLeaseExpires() - PhabricatorTime::getNow(); + $twenty_percent = max($this->getRequiredLeaseTime() * 0.2, 10); + if ($time_left < $twenty_percent) { + $this->activeTask->setLeaseDuration( + $this->activeTask->getLeaseExpires() - + $this->activeTask->getServerTime() + + $this->getRequiredLeaseTime()); + + if ($this->daemon !== null) { + $this->daemon->stillWorking(); + } + } + } + /** * Wait for tasks to complete. If tasks are not leased by other workers, they diff --git a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php --- a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php +++ b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php @@ -52,6 +52,10 @@ return $this; } + public function getServerTime() { + return $this->serverTime; + } + public function setLeaseDuration($lease_duration) { $this->checkLease(); $server_lease_expires = $this->serverTime + $lease_duration; @@ -129,7 +133,7 @@ return $archive; } - public function executeTask() { + public function executeTask(PhutilDaemon $daemon = null) { // We do this outside of the try .. catch because we don't have permission // to release the lease otherwise. $this->checkLease(); @@ -138,6 +142,7 @@ $worker = null; try { $worker = $this->getWorkerInstance(); + $worker->setDaemon($daemon); $maximum_failures = $worker->getMaximumRetryCount(); if ($maximum_failures !== null) { diff --git a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php --- a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php +++ b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php @@ -57,7 +57,6 @@ } final public function getWorkerInstance() { - $id = $this->getID(); $class = $this->getTaskClass(); if (!class_exists($class)) { @@ -70,7 +69,7 @@ "Task class '{$class}' does not extend PhabricatorWorker."); } - return newv($class, array($this->getData())); + return newv($class, array($this, $this->getData())); } }