这是我的问题:
在我的数据库中,我有一个请求表,它有一个状态字段。 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).')');
我选择它后将状态设置为处理,这会阻止其他脚本处理它,但是一个脚本是否可能选择所有请求,然后第二个脚本在第一个脚本将它们设置为之前选择所有请求处理?
我想要一种更安全的方式来做到这一点!
编辑:感谢您提供了很好的答案,但在我将其标记为正确之前,我必须先试用它们。
答案 0 :(得分:2)
您可以尝试制作一个锁定/解锁文件,以便cronjobs可以检查“知道”作业是否已经/正在运行。 如果出现故障,没有响应等,也可以使用进程pid来识别进程的状态。
答案 1 :(得分:1)
将状态设置为唯一值,然后使用该唯一值处理所有内容。如果您的处理在一半时间内失败,则会出现超时或某种后退(但无论如何您需要处理当前情况)。
类似的东西(我只是编造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作业的锁文件可以在不改变代码的情况下轻松完成。
答案 2 :(得分:0)
transactions是你想要的。因此,您只需一个事务来读取数据,将待处理状态更改为某个中间值(如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