Skip to content

Commit 990d0e6

Browse files
authored
Merge pull request #80 from tarosky/issue/79
Handle orphaned cron jobs Close #79.
2 parents 677586e + 0d7b3b8 commit 990d0e6

10 files changed

Lines changed: 97 additions & 9 deletions

File tree

build/build-image

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ set -eu
44

55
# shellcheck disable=SC1091
66
source build/envs.sh
7-
exec docker-compose -f build/docker-compose.yml build
7+
exec docker compose -f build/docker-compose.yml build

build/docker-compose.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
version: '3.9'
21
services:
32
wordpress:
43
build:

build/run-package

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ set -eu
44

55
# shellcheck disable=SC1091
66
source build/envs.sh
7-
exec docker-compose -f build/docker-compose.yml run --rm cavalcade-runner package
7+
exec docker compose -f build/docker-compose.yml run --rm cavalcade-runner package

build/run-test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
set -eu
44

5-
trap 'docker-compose -f build/docker-compose.yml down' EXIT
5+
trap 'docker compose -f build/docker-compose.yml down' EXIT
66

77
# shellcheck disable=SC1091
88
source build/envs.sh
9-
docker-compose -f build/docker-compose.yml run --rm wordpress
9+
docker compose -f build/docker-compose.yml run --rm wordpress

build/run-validate

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ set -eu
44

55
# shellcheck disable=SC1091
66
source build/envs.sh
7-
exec docker-compose -f build/docker-compose.yml run --rm cavalcade-runner validate
7+
exec docker compose -f build/docker-compose.yml run --rm cavalcade-runner validate

build/wordpress/entrypoint

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,4 @@ cat "$ctrl_done_fifo" > /dev/null
4848
mv work/log work/test-logs/entrypoint
4949

5050
vendor/bin/phpunit --log-junit work/test-result.xml
51+
# vendor/bin/phpunit --log-junit work/test-result.xml --filter test_ms_single_event_without_siteid

inc/class-job.php

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,19 @@ function ($stmt) {
9393
$stmt->execute();
9494

9595
$data = $stmt->fetch(PDO::FETCH_OBJ);
96+
if ($data === false) {
97+
return false;
98+
}
99+
96100
return $data->domain . $data->path;
97101
},
98102
true,
99103
);
100104

105+
if ($res === false) {
106+
throw new SiteNotFoundException('site id not found');
107+
}
108+
101109
$this->log->debug('site url', ['siteurl' => $res] + $this->log_values());
102110

103111
return $res;
@@ -120,11 +128,14 @@ public function acquire_lock()
120128
$nextrun = DateTime::createFromFormat('Y-m-d H:i:s', $this->nextrun, new DateTimeZone('UTC'));
121129
$this->execution_delay = $started_at->getTimestamp() - $nextrun->getTimestamp();
122130

131+
$this->status = 'running';
132+
123133
$res = $this->db->prepare_query(
124134
"UPDATE `$this->table`
125-
SET `status` = 'running', `started_at` = :started_at
135+
SET `status` = :status, `started_at` = :started_at
126136
WHERE `status` = 'waiting' AND id = :id",
127137
function ($stmt) {
138+
$stmt->bindValue(':status', $this->status);
128139
$stmt->bindValue(':id', $this->id, PDO::PARAM_INT);
129140
$stmt->bindValue(':started_at', $this->started_at);
130141
$stmt->execute();
@@ -147,12 +158,17 @@ public function cancel_lock()
147158
{
148159
$this->log->debug('canceling lock', $this->log_values());
149160

161+
$this->status = 'waiting';
162+
$this->started_at = null;
163+
150164
$this->db->prepare_query(
151165
"UPDATE `$this->table`
152-
SET `status` = 'waiting', `started_at` = NULL
166+
SET `status` = :status, `started_at` = :started_at
153167
WHERE id = :id",
154168
function ($stmt) {
169+
$stmt->bindValue(':status', $this->status);
155170
$stmt->bindValue(':id', $this->id, PDO::PARAM_INT);
171+
$stmt->bindValue(':started_at', $this->started_at);
156172
$stmt->execute();
157173
},
158174
true,
@@ -172,11 +188,14 @@ public function mark_done()
172188
$this->reschedule();
173189
$this->log->debug('rescheduled', $this->log_values());
174190
} else {
191+
$this->status = 'done';
192+
175193
$this->db->prepare_query(
176194
"UPDATE `$this->table`
177-
SET `status` = 'done', `finished_at` = :finished_at
195+
SET `status` = :status, `finished_at` = :finished_at
178196
WHERE `id` = :id",
179197
function ($stmt) {
198+
$stmt->bindValue(':status', $this->status);
180199
$stmt->bindValue(':id', $this->id, PDO::PARAM_INT);
181200
$stmt->bindValue(':finished_at', $this->finished_at);
182201
$stmt->execute();

inc/class-runner.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,10 @@ protected function run_job($job)
604604
@fclose($pipes[2]);
605605
throw new Exception('failed to set stdout to non-blocking');
606606
}
607+
} catch (SiteNotFoundException $e) {
608+
$job->mark_done();
609+
$this->log->error_app('job failed; failed to get site id for job', $job->log_values_full());
610+
return;
607611
} catch (Exception $e) {
608612
$this->log->error('exception during starting job', [
609613
'ex_message' => $e->getMessage(),
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace HM\Cavalcade\Runner;
4+
5+
use RuntimeException;
6+
7+
class SiteNotFoundException extends RuntimeException
8+
{
9+
public function __construct($message)
10+
{
11+
parent::__construct($message);
12+
}
13+
}

test/test-job.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,58 @@ public function test_single_event()
7474
$this->assertNull($this->get_job(JOB));
7575
}
7676

77+
public function test_ms_single_event_without_siteid()
78+
{
79+
global $wpdb;
80+
81+
if (getenv('WP_MULTISITE') !== '1') {
82+
$this->markTestSkipped('Not multisite');
83+
return;
84+
}
85+
86+
$pre_time = time();
87+
wp_schedule_single_event($pre_time, JOB, [__FUNCTION__]);
88+
$job = $this->get_job(JOB);
89+
$wpdb->query("UPDATE `$this->table` SET `site` = 9999 WHERE `id` = $job->id");
90+
$this->assertEquals(STATUS_WAITING, $job->status);
91+
$this->assertNull($job->started_at);
92+
$this->assertNull($job->finished_at);
93+
94+
sleep(3);
95+
96+
$post_time = time();
97+
$job = $this->get_job(JOB);
98+
$this->assertEquals(STATUS_DONE, $job->status);
99+
$this->assertBetweenWeak($pre_time, $post_time, self::as_epoch($job->started_at));
100+
$this->assertBetweenWeak($pre_time, $post_time, self::as_epoch($job->finished_at));
101+
$this->assertEquals(EMPTY_DELETED_AT, $job->deleted_at);
102+
103+
$this->assertBetweenWeak(
104+
strtotime('-1 minutes'),
105+
time(),
106+
self::as_epoch($job->nextrun),
107+
);
108+
109+
sleep(3);
110+
111+
$job = $this->get_job(JOB);
112+
$this->assertEquals(STATUS_DONE, $job->status);
113+
114+
sleep(6);
115+
116+
$this->assertNull($this->get_job(JOB));
117+
118+
$log_lines = explode("\n", file_get_contents(RUNNER_LOG));
119+
foreach ($log_lines as $line) {
120+
if (strstr($line, '"ERROR"') !== false) {
121+
$this->assertStringContainsString('"job failed; failed to get site id for job"', $line);
122+
$this->assertStringContainsString('"app"', $line);
123+
return;
124+
}
125+
}
126+
$this->fail();
127+
}
128+
77129
public function test_deleted_event()
78130
{
79131
global $wpdb;

0 commit comments

Comments
 (0)