-
Notifications
You must be signed in to change notification settings - Fork 9.3k
/
Schedule.php
111 lines (103 loc) · 3.49 KB
/
Schedule.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Cron\Model\ResourceModel;
/**
* Schedule resource
*
* @api
* @since 100.0.2
*/
class Schedule extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
{
/**
* Initialize resource
*
* @return void
*/
public function _construct()
{
$this->_init('cron_schedule', 'schedule_id');
}
/**
* Sets new schedule status only if it's in the expected current status.
*
* If schedule is currently in $currentStatus, set it to $newStatus and
* return true. Otherwise, return false.
*
* @param string $scheduleId
* @param string $newStatus
* @param string $currentStatus
* @return bool
*/
public function trySetJobStatusAtomic($scheduleId, $newStatus, $currentStatus)
{
$connection = $this->getConnection();
$result = $connection->update(
$this->getTable('cron_schedule'),
['status' => $newStatus],
['schedule_id = ?' => $scheduleId, 'status = ?' => $currentStatus]
);
if ($result == 1) {
return true;
}
return false;
}
/**
* Sets schedule status only if no existing schedules with the same job code have that status.
*
* This is used to implement locking for cron jobs.
* If the schedule is currently in $currentStatus and there are no existing
* schedules with the same job code and $newStatus, set the schedule to
* $newStatus and return true. Otherwise, return false.
*
* @param string $scheduleId
* @param string $newStatus
* @param string $currentStatus
* @return bool
* @since 100.2.0
*/
public function trySetJobUniqueStatusAtomic($scheduleId, $newStatus, $currentStatus)
{
$connection = $this->getConnection();
$connection->beginTransaction();
// this condition added to avoid cron jobs locking after incorrect termination of running job
$match = $connection->quoteInto(
'existing.job_code = current.job_code ' .
'AND existing.status = ? ' .
'AND (existing.executed_at > UTC_TIMESTAMP() - INTERVAL 1 DAY OR existing.executed_at IS NULL)',
$newStatus
);
// Select and lock all related schedules - this prevents deadlock in case cron overlaps and two jobs of
// the same code attempt to lock at the same time, and force them to serialize
$selectIfUnlocked = $connection->select()
->from(
['current' => $this->getTable('cron_schedule')],
[]
)
->joinLeft(
['existing' => $this->getTable('cron_schedule')],
$match,
['existing.schedule_id']
)
->where('current.schedule_id = ?', $scheduleId)
->where('current.status = ?', $currentStatus)
->forUpdate(true);
$scheduleId = $connection->fetchOne($selectIfUnlocked);
if (!empty($scheduleId)) {
// Existing running schedule found
$connection->commit();
return false;
}
// Mark our schedule as running
$connection->update(
$this->getTable('cron_schedule'),
['status' => new \Zend_Db_Expr($connection->quote($newStatus))],
['schedule_id = ?' => $scheduleId]
);
$connection->commit();
return true;
}
}