【问题标题】:Endless loop in cron job phpcron作业php中的无休止循环
【发布时间】:2014-08-16 07:02:49
【问题描述】:

我必须向用户发送大量电子邮件。我想在一个 cron 作业中有一个无限循环,我想获取几十或几百个用户并一个接一个地发送电子邮件 - 更新表格,表明电子邮件已发送。而且我应该设置一些睡眠间隔,只要每包十几个(或一百个)用户收到电子邮件。基本上是这样的

while(1 != 0) {
$notifications = // fetch notifications, where email is not sent

foreach($notifications as $notification) {
    // 1) send email
    // 2) update table - email was sent
}

sleep(5);
}

现在,这可以使用吗,还是被认为是一种不好的做法?

我知道,我也可以使用多个 cron,假设每分钟一次,但是为了防止在使用锁定文件时重叠,只要 cron 启动并且锁定文件存在(因此另一个 cron 仍在运行),它应该要么

a) wait for some time to the first cron to finish, to start, 
or 
b) just return empty, allowing the next cron to do the job ASA the ongoing one is done. 

a) 的问题在于,如果 crons 花费的时间比预期的多,那么一段时间后,我将有一堆 crons 处于“等待”状态。关于b) 的情况,如果在第二个 cron 完成后(返回空),第一个 cron 结束,那么我将有大约一分钟的间隔,我需要尽快向用户发送电子邮件。

另外,qsn 2,在性能方面,一个 cron 循环与多个 crons 哪个更好?

谢谢

【问题讨论】:

  • 我个人认为在 cron 作业中设置无限循环并不是一个好主意。 Cron 适用于需要在特定时间或时间间隔重复的任务,那么下次您的 cron 作业触发时会发生什么?
  • @watcher,感谢您的评论,好点子!但似乎有一个解决方案serverfault.com/questions/111609/…
  • 与mysql标签有什么关系?,反正个人id为此创建了一个upstart守护进程[Example, Run PHP script as daemon process],因为inf循环,它会干净得多,而且没有多个正在运行的实例。
  • 正如@watcher crons 提到的用于定期任务,你需要的是一个守护进程(我不知道 PHP 是否适合它,一些阅读 kvz.io/blog/2009/01/09/create-daemons-in-php
  • 说到性能,为什么每封邮件都更新表格?如果您发送 1000 封电子邮件,您不想进行 1000 次查询。存储所有更新的 id 数组,完成后只需在 1 个查询中更新它们?

标签: php mysql cron


【解决方案1】:

您描述的是守护进程,而不是 cron 任务。

有很多守护进程连续运行,所以不,这样做不是一个坏习惯。

如果您希望守护程序在崩溃时自动重新启动,您可以设置一个看门狗任务,它会持续检查守护程序是否正在运行,如果没有运行,则启动一个守护进程。

另一种选择(如您所描述的)是让 crontask 偶尔尝试启动守护进程;启动应该检测守护进程是否已经在运行。如果它已经在运行,请保留它,然后退出。如果它没有运行,则启动另一个(在后台,作为一个分离的进程。无论哪种方式,crontask 都会很快完成。

(守护进程是否连接到 MySQL 无关紧要。)

【讨论】:

  • 感谢您的回答,(@Loz Cherone ツ 也在评论中提到)我不知道守护进程,将看看并尝试一下
【解决方案2】:

就个人而言,我不喜欢无限循环。例如,我更喜欢 cron 作业5 分钟 运行一次。 您可以优化脚本以在 cron 作业时间内发送最大电子邮件数量。

您需要估计每分钟发送多少封电子邮件。我假设 每秒 1 封电子邮件


所以我的想法是:

  1. 查询 290 个通知 [获取和更新通知延迟 10 秒] 并将它们标记为“sending”状态(以防止下一个 cron 不选择它们)。
  2. 发送电子邮件并将结果保存在数组中(供以后更新)。
  3. 完成后,更新通知状态(已发送或错误)。


只是我的 2 美分。

【讨论】:

  • 感谢您的回答,关键是我无法估计电子邮件的发送,如果其中一个延迟很长,可能是某些电子邮件服务器已关闭或响应时间较晚
  • 好的,那么您应该“谨慎行事”,例如每 5 秒发送 1 封电子邮件。仅更改您的 LIMIT 条件(根据查询)。但这不是你真正的问题。我认为主要是重叠 cron 作业。有了我的解决方案,你就没有这个问题了。
  • 将状态设置为待处理有一些问题 IMO。首先,如果 cron 作业由于某种原因停止,则永远不会再次发送状态为“正在发送”的电子邮件,其次,将状态更新为“正在发送”是一个额外的查询。谢谢
  • 您可以改进您的第一个查询,在最后 1 小时前选择状态为“正在发送”:SELECT * FROM notifications WHERE (status = 'sending' AND created_at
猜你喜欢
  • 2020-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-09
  • 2017-08-29
  • 2021-06-18
  • 2021-12-30
  • 1970-01-01
相关资源
最近更新 更多