1

这是我的问题:

在我的数据库中,我有一个请求表,其中有一个状态字段。cronjob 每分钟运行一次,以“待定”状态查找每个请求。当它完成处理请求时,它将状态设置为“完成”。

有时,这个 cronjob 需要超过一分钟才能运行,因此有两个相同的 cronjob 正在运行。我需要确保他们不会处理相同的请求。

现在我正在这样做:

$requests = db_all($this->db->query('SELECT * FROM x__mx_request WHERE status="pending"'));
//few lines of code later
$this->db->query('UPDATE x__mx_request SET status="processing" WHERE id IN('.implode(',', $ids).')');

我选择它后将状态设置为处理,这也阻止其他脚本处理它,但是一个脚本是否可能选择所有请求,然后第二个脚本在第一个脚本将它们设置为处理之前选择所有请求?

我想要一种更安全的方式来做到这一点!

编辑:感谢您提供的出色答案,但我必须先实际尝试一下,然后才能将其标记为正确。

4

3 回答 3

2

您可以尝试制作一个锁定/解锁文件,以便 cronjobs 可以检查以“知道”作业是否正在运行/尚未运行。进程 pid 也可用于识别进程状态,以防万一发生故障、无响应等。

于 2012-05-07T18:53:28.030 回答
2

将状态设置为唯一值,然后处理具有该唯一值的所有内容。如果您的处理中途失败,请进行超时或某种回退(但无论如何您都需要在当前情况下这样做)。

类似的东西(我只是在编 PHP,因为我不是特别了解该语言):

 $guid = new_guid();

 $this->db->query(
    'UPDATE x__mx_request SET status = ? WHERE status = "pending";', 
    $guid
 );
 $requests = db_all(
    $this->db->query('SELECT * FROM x__mx_request WHERE status = ?;', $guid)
 );

另一种选择是事务-但我认为您需要SERIALIZABLE,这意味着您基本上只能处理一项工作。如果您想这样做,您的 cron 作业的锁定文件可以让您轻松完成此操作,而无需更改代码。

于 2012-05-07T18:56:23.257 回答
0

交易是你想要的。因此,您有一个读取数据、将挂起状态更改为某个中间值(例如 inprocess)并返回数据的事务。

这可以防止两个查询返回相同的数据。

大致你想要这样的伪 sql

begin transaction 

select into tmp table * from blah where status = "pending"

update status = "being processed" where id in tmp 

end transaction 

return select * from tmp table
于 2012-05-07T18:48:50.107 回答