我在Symfony中有一个需要从应用程序发送电子邮件/通知的应用程序。 由于电子邮件/通知发送过程需要时间,因此我决定将它们放入队列并定期处理队列。因此,我可以减少涉及电子邮件/通知发送的请求的响应时间。
处理队列的Cron Job(一个php脚本 - Symfony路由)每30秒运行一次,并检查是否有任何未发送的电子邮件/通知,如果发现它从队列表中获取所有数据并开始发送它们。发送电子邮件/通知时,队列表行状态标志会更新以显示已发送。
现在,当队列中有更多的电子邮件时,可能需要超过30秒才能发送。另一个Cron Job也开始运行并开始从Queue发送电子邮件。因此导致重复的电子邮件/通知发送。
我的电子邮件队列表结构如下:
|-------------------------------------|
| id | email | body | status | sentat |
|-------------------------------------|
我解决此问题的想法如下:
所以我的问题是,是否有任何有效的方法来处理队列?是否有任何Symfony Bundle / Feature可以执行此类特定任务?
答案 0 :(得分:2)
关于你的建议:
如果cronjob进程死亡(无论出于何种原因)并且无法清除标志怎么办?我想,旗帜并不是一个好主意。如果您想要遵循这种方法,则不应使用布尔值,而应使用进程ID或时间戳,这样您就可以检查进程是否仍处于活动状态,或者它是否在很长时间内开始运行而未进行清理。
同样的问题:如果这个过程死了怎么办?您不希望在 发送之前将邮件标记为已发送。
我想我可能会使用两个字段:一个用于将记录标记为“正在发送”(因此告诉其他进程跳过此记录),另一个用于将其标记为“发送成功完成”。我给两者写了一个时间戳,这样我就可以(自动或手动)找到那些“正在发送”的记录。过去X秒,这将是死亡过程的指标。
答案 1 :(得分:2)
所以我的问题是,是否有任何有效的方法来处理队列?是否有任何Symfony Bundle / Feature可以执行此类特定任务?
您可以enqueue-bundle加doctrine dbal transport。
它已经处理了竞争条件和其他事情。
答案 2 :(得分:1)
您可以在此处使用数据库事务。 Rest将由数据库锁定机制和并发控制处理。通常,无论您提供什么DML / DCL / DDL命令,都将被视为隔离事务。在你的问题中,如果第二个cron作业将读取行(在第一个cron作业将更新它之前发送),它将发现未发送的电子邮件,并尝试再次发送它。并且在第二个cron作业将更新为发送之前,如果第三个作业将发现它未发送,它将执行相同的操作。所以它可能会给你带来很大的麻烦。
无论你采取何种方法,都会有种族条件。所以让数据库允许这样做。你可以参考很多并发控制方法。
BEGIN_TRANSACTION
/* Perform your actions here. N numbers of read/write */
END_TRANSACTION
此解决方案仍存在一个问题。您将在一个阶段发现,当读/写操作的数量增加时,仍然存在一些不一致。
这是数据库的隔离级别,它是定义彼此隔离多少2个事务的因素,以及如何安排它们同时运行。
您可以根据自己的要求设置隔离级别。请记住,并发性与隔离级别成反比。因此,分析您的读/写语句,找出您需要的级别。不要使用更高级别。我正在提供一些可能对您有用的链接
http://www.ibm.com/developerworks/data/zones/informix/library/techarticle/db_isolevels.html
Difference between read commit and repeatable read
http://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.htm
如果您可以在此处发布数据库操作。我可以建议你一些可能的隔离级别