我们有一项工作,希望每隔一段时间在两台单独的服务器上运行。该作业通过实质上每分钟一次将队列记录转换为SMTP消息来处理电子邮件队列。它可以在单个服务器上很好地工作,但是我们希望避免出现单点故障,并在两个(或更多)服务器中的每一个上交替运行该作业。
最好不要同时运行这些作业,因此我希望其中一个能够检测到另一个正在运行并停止而无需做任何工作。基本上,他们不应该踩到对方的脚趾。
这与How to Prevent Sql Server Jobs to Run simultaneously相似,但有两个细节:
我的第一个直觉是使用类似于以上答案所示的数据库。在MariaDB中,我可能为此目的创建一个“锁”表,并使用如下代码:
CREATE TABLE locks (id VARCHAR 10, PRIMARY KEY id);
INSERT INTO locks (id) VALUES ('email');
BEGIN;
SELECT id FROM locks WHERE id='email' FOR UPDATE;
[do my work, here, in another connection/transaction]
ROLLBACK; // or COMMIT
我期望FOR UPDATE将导致锁定记录被锁定,直到我COMMIT
或ROLLBACK
该事务为止。这意味着另一个试图执行相同代码的进程应阻止等待锁定。如果我在该SELECT
查询上添加了超时,则可以检测到超时并仅停止“第二”过程而无需继续“实际工作”。
该计划会按我期望的方式工作吗?具体来说:
SELECT ... FOR UPDATE
是否真的持有锁,直到事务完成。我相信答案是是-很好,我希望如此,因为我还有很多其他依赖这种技术的代码。SELECT ... FOR UPDATE
将仅锁定一行,还是数据库将锁定多于一行?我希望能够在许多不同的工作上使用此技术,其中只有一项是“电子邮件”工作。如有必要,我可以为每种作业类型创建单独的表。我们还没有使用集群数据库,但是我们希望朝着这个方向发展,因此,首选在这种环境下也可以运行的解决方案。