From 136756293b76233fff5089b89451f1774dba41dc Mon Sep 17 00:00:00 2001 From: Ben Roberts Date: Sat, 4 Sep 2010 18:33:51 +0100 Subject: [PATCH] Improvements to Status Handling Added link to jobs page to fix any issues caused by non-synchronised time between webserver/worker machine leaving jobs permanently in the running state. Prevented the insertion of new status records unless the state is actually being changed. Made the HandBrake worker process write the status complete message instead of the run-jobs dispatched, in case it crashes. --- lib/RippingCluster/Job.class.php | 38 ++++++++++++++++-- lib/RippingCluster/JobStatus.class.php | 21 ++++++++-- .../Worker/Plugin/HandBrake.class.php | 2 + webui/images/clock.png | Bin 0 -> 1251 bytes webui/pages/jobs.php | 6 +++ webui/run-jobs.php | 19 --------- webui/templates/jobs.tpl | 3 ++ 7 files changed, 64 insertions(+), 25 deletions(-) create mode 100644 webui/images/clock.png diff --git a/lib/RippingCluster/Job.class.php b/lib/RippingCluster/Job.class.php index f0687c1..1544584 100644 --- a/lib/RippingCluster/Job.class.php +++ b/lib/RippingCluster/Job.class.php @@ -22,6 +22,10 @@ class RippingCluster_Job { private $audio_names; private $subtitle_tracks; + /** + * + * @var array(RippingCluster_JobStatus) + */ private $statuses = null; private static $cache = array(); @@ -269,8 +273,13 @@ class RippingCluster_Job { public function updateStatus($new_status, $rip_progress = null) { $this->loadStatuses(); - $new_status = RippingCluster_JobStatus::updateStatusForJob($this, $new_status, $rip_progress); - $this->statuses[] = $new_status; + + // Only update the status if the state is changing + if ($this->currentStatus()->status() != $new_status) { + $new_status = RippingCluster_JobStatus::updateStatusForJob($this, $new_status, $rip_progress); + $this->statuses[] = $new_status; + } + return $new_status; } @@ -289,7 +298,30 @@ class RippingCluster_Job { return $remaining_time; } - + + public function fixBrokenTimestamps() { + $this->loadStatuses(); + + // See if we have both a RUNNING and a COMPLETE status set + $statuses = array(); + foreach ($this->statuses as $status) { + switch ($status->status()) { + case RippingCluster_JobStatus::RUNNING: + case RippingCluster_JobStatus::COMPLETE: + $statuses[$status->status()] = $status; + break; + } + } + + if (isset($statuses[RippingCluster_JobStatus::RUNNING]) && isset($statuses[RippingCluster_JobStatus::COMPLETE])) { + // Ensure the timestamp on the complete is >= that of the running status + if ($statuses[RippingCluster_JobStatus::COMPLETE]->mtime() < $statuses[RippingCluster_JobStatus::RUNNING]->mtime()) { + $statuses[RippingCluster_JobStatus::COMPLETE]->mtime($statuses[RippingCluster_JobStatus::RUNNING]->mtime() + 1); + $statuses[RippingCluster_JobStatus::COMPLETE]->save(); + } + } + } + public function id() { return $this->id; } diff --git a/lib/RippingCluster/JobStatus.class.php b/lib/RippingCluster/JobStatus.class.php index 95448f3..eab70cc 100644 --- a/lib/RippingCluster/JobStatus.class.php +++ b/lib/RippingCluster/JobStatus.class.php @@ -68,7 +68,7 @@ class RippingCluster_JobStatus { } return $statuses; - } + } protected function create() { $database = RippingCluster_Main::instance()->database(); @@ -104,11 +104,22 @@ class RippingCluster_JobStatus { ) ); } - + public function hasProgressInfo() { return ($this->status == self::RUNNING); } + public static function fixBrokenTimestamps() { + $statuses = array(); + + $database = RippingCluster_Main::instance()->database(); + foreach ($database->selectList('SELECT * FROM job_status WHERE status=4 AND job_id IN (SELECT job_id FROM job_status WHERE status=3)') as $row) { + $status = RippingCluster_JobStatus::fromDatabaseRow($row); + $status->mtime = time(); + $status->save(); + } + } + public function id() { return $this->id; } @@ -129,7 +140,11 @@ class RippingCluster_JobStatus { return $this->ctime; } - public function mtime() { + public function mtime($new_mtime = null) { + if ($new_mtime !== null) { + $this->mtime = $new_mtime; + } + return $this->mtime; } diff --git a/lib/RippingCluster/Worker/Plugin/HandBrake.class.php b/lib/RippingCluster/Worker/Plugin/HandBrake.class.php index 719881d..b171e56 100644 --- a/lib/RippingCluster/Worker/Plugin/HandBrake.class.php +++ b/lib/RippingCluster/Worker/Plugin/HandBrake.class.php @@ -82,6 +82,8 @@ class RippingCluster_Worker_Plugin_HandBrake implements RippingCluster_Worker_IP list($return_val, $stdout, $stderr) = RippingCluster_ForegroundTask::execute($handbrake_cmd, null, null, null, array($this, 'callbackOutput'), array($this, 'callbackOutput'), $this); if ($return_val) { $this->gearman_job->sendFail($return_val); + } else { + $this->job->updateStatus(RippingCluster_JobStatus::COMPLETE); } } diff --git a/webui/images/clock.png b/webui/images/clock.png new file mode 100644 index 0000000000000000000000000000000000000000..ca8c14b052488baf9015a2ae31ff9c3732e52d0b GIT binary patch literal 1251 zcmV<91RVQ`P) z@AoF?z~wFXo^!wVoV%QRLyXb?S?X&w5JIR&2d1JE*mdXVe6UEAThgm-E=J zrR7XtRvD27JeEad6+&)6T%CpEuFdqFM)V9oz z7Axh1yeM8ulZEaE!Da+!SN{El&@V+sy8mtX_lt^U}o_ zciIO>k@X&Eo1km%k5=SVKMgMrrg}qM+a#R%k>CsYUcn{7PPA!}A<86FoluJzB(z)EqX%~2)O28M0_IDr=;xgCr;vmY8t^{E7>^uQS!N{D@hx7%xUux)DBfEmoxewn zsH>oGH2$Qzxl<$DwbCBkQ?`B-#q*^(@emsRBe+{KxZ5hW*^Pl^*d|>ACXFFj3C~H7 z1J{k(whCkOrE_t!^d?x?n^LxPj+B)CfD?DCQ>Ed3@Sv14Zp3Ank^^jlbl?3v3+XeM zQH}11ZDu#y!GY3a(o*S|{6M-x^k!b}mtIu|o`d(pDbf>Oz4Z8bbBytmsyi(hsy1nU zKA(lE(i8C3YycOdy+~iVJXlFW2qozuy*=~PCTxl^Zmrq&SOET)@-MVwX5VUu>+Jvl N002ovPDHLkV1n@_RD=Kk literal 0 HcmV?d00001 diff --git a/webui/pages/jobs.php b/webui/pages/jobs.php index 4549f99..aea9ced 100644 --- a/webui/pages/jobs.php +++ b/webui/pages/jobs.php @@ -52,6 +52,12 @@ if ($req->get('submit')) { $job->delete(); } } break; + + case 'fix-broken-timestamps': { + foreach ($jobs as $job) { + $job->fixBrokenTimestamps(); + } + } break; default: { throw new RippingCluster_Exception_InvalidParameters('action'); diff --git a/webui/run-jobs.php b/webui/run-jobs.php index 58581ec..d553603 100644 --- a/webui/run-jobs.php +++ b/webui/run-jobs.php @@ -44,9 +44,6 @@ function gearman_created_callback($gearman_task) { $main = RippingCluster_Main::instance(); $log = $main->log(); - $job = RippingCluster_Job::fromId($gearman_task->unique()); - $job->updateStatus(RippingCluster_JobStatus::QUEUED); - $log->info("Job successfully queued with Gearman", $gearman_task->unique()); } @@ -57,26 +54,10 @@ function gearman_data_callback($gearman_task) { $log->debug("Received data callback from Gearman Task"); } -function gearman_status_callback($gearman_task) { - $main = RippingCluster_Main::instance(); - $log = $main->log(); - - $job = RippingCluster_Job::fromId($gearman_task->unique()); - $status = $job->currentStatus(); - - $rip_progress = $gearman_task->taskNumerator() / $gearman_task->taskDenominator(); - if ($rip_progress > $status->ripProgress() + 0.1) { - $status->updateRipProgress($rip_progress); - } -} - function gearman_complete_callback($gearman_task) { $main = RippingCluster_Main::instance(); $log = $main->log(); - $job = RippingCluster_Job::fromId($gearman_task->unique()); - $job->updateStatus(RippingCluster_JobStatus::COMPLETE); - $log->info("Job Complete", $job->id()); } diff --git a/webui/templates/jobs.tpl b/webui/templates/jobs.tpl index cd9e6fd..74773f9 100644 --- a/webui/templates/jobs.tpl +++ b/webui/templates/jobs.tpl @@ -26,6 +26,7 @@ + @@ -60,6 +61,7 @@ + @@ -72,6 +74,7 @@ + {else}