【发布时间】:2017-03-25 10:53:26
【问题描述】:
我正在尝试限制从我的网站发送的电子邮件数量,以应对托管服务电子邮件的限制。 我正在使用 cron 作业和在数据库中堆积电子邮件的指示器来检查发送的电子邮件数量是否接近发送的最大电子邮件数量的限制。
我这样做的方式是直接执行预定的进程,然后让它“休眠”一段时间(根据它在队列中的位置),然后发送电子邮件并登录数据库。 为了进一步解释我使用计划任务和“睡眠”的原因,请考虑以下场景:
- 用户尝试注册到我的网站,并希望尽快向他/她发送一封电子邮件。因此,如果超出电子邮件/分钟配额,我需要发送一条不同的消息:“我们的服务器正忙,请允许 'x' 分钟来执行所需的任务”。
- 发送电子邮件的请求都是通过 AJAX 完成的。在进程本身中使用“睡眠”不是一种选择,因为用户将不得不等待 x 分钟,直到“忙碌消息”被回显。
- 我尝试过使用 ob_flush、flush...等。组合来回显消息,然后服务器在后台解决所有问题,但这从来没有奏效。 AJAX 调用一直在等待脚本结束以回显结果。
我需要单线程 PHP 语言中的多线程!作为一种解决方法,我使用了 cron 作业,其中每个堆积的电子邮件都计划在
time()执行(即直接触发预定的作业),它与发送电子邮件的相同功能挂钩。使用标志,该函数知道请求是堆积的电子邮件,并使其“休眠”,直到电子邮件配额重置所需的时间。问题:如果 5 个人几乎同时注册(而我们还有一堆电子邮件),那么我们有 5 个 cron 作业应该同时执行,然后休眠一段时间(如果堆中的电子邮件数量已经大于电子邮件配额,则睡眠时间可能会有所不同),然后发送电子邮件。但是,当我检查数据库中的日志时,我发现计划的作业是按顺序执行的,而不是并行执行的。有时会发生 cron 作业在另一端之前触发,但它们不会同时触发。
我知道 wordpress cron 作业并不是真正的 cron 作业,一旦有人访问该网站就会被解雇(并且我确保在发送注册请求以触发所有计划任务后刷新页面),但它们似乎对我来说是唯一的选择,因为我的托管服务器不允许访问服务器,也不允许安排 cron 作业。
这是执行上述代码的部分代码:
//Test example to pile up emails, where quota is set to 2 emails every 30 seconds
$Emails_Threshold = 2;
$Threshold_Duration = 0.5*60;
//Get email indicator info
$Email_Info = $wpdb->get_row(
"SELECT *
FROM PileEmails
WHERE priority = -1
AND Status='New';"
,ARRAY_A);
if ($sleep ==0 && $Queue_Info_id==0){ //Not a scheduled event
//Check if there are queued emails
$Queue_exist = $wpdb->get_row (
$wpdb->prepare("
SELECT Status
FROM PileEmails
WHERE Status='Queued';"
,$mail_priority)
,ARRAY_A);
if (!empty($Queue_exist) || ($Email_Info['last_email_time'] > (time()-$Threshold_Duration))){
if ($Email_Info['count_emails']>=$Emails_Threshold){
//Code to Pile up
}
}else{
//Reset email counter
}
}else{
$wpdb->insert( "PileEmails",$Sleep_Info,$format);
sleep(10); //10 seconds here just as an example
}
//Code to send emails
这是我在超过配额后尝试发送 10 封电子邮件时登录到数据库的内容。
请注意,每个日志和下一个日志之间的时间戳有 10 秒的差异,尽管它们应该同时被触发并且每个都休眠 10 秒,然后都并行发送电子邮件。
所以我的问题是:为什么 wordpress cron 按顺序而不是并行触发预定的作业?以及如何克服这个问题?
非常感谢任何帮助。
【问题讨论】:
-
也许我应该指出我在编译上面的代码时遇到的一个 wordpress 问题:当你做一个 wordpress cron 作业“睡眠”时,这意味着每当有人在此期间访问你的网站时,它将再次执行它睡着了……即如果计划任务未完成,wordpress 将再次重新启动它,因为它仍然可以看到 cron 作业。我认为这是 wordpress 人员应该解决的问题,没有人期望一个 cron 作业在非常接近的时间间隔内执行多次。
-
显然 wordpress 在他们的网站上所说的:“请注意,将事件安排在同名的现有事件之后 10 分钟之前发生将被忽略,除非您将 $args 的唯一值传递给每个已安排的event." 表示 wordpress 不允许在 10 分钟内多次“调度”同一个脚本,同时它还应该防止在某个时间跨度内多次“执行”同一个调度脚本。
-
我建议首先安装一个 cron 管理插件,这样您就可以轻松查看何时以及是否触发了哪些 cron,或者查看此处以创建您自己的 developer.wordpress.org/plugins/cron/simple-testing