wordpress cron 作业是顺序执行还是并行执行?

Posted

技术标签:

【中文标题】wordpress cron 作业是顺序执行还是并行执行?【英文标题】:Are wordpress cron jobs executed sequentially or in parallel? 【发布时间】: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 【参考方案1】:

如前所述,安装 cron 插件将有助于管理您的 cron。

为了回答您的问题,Wordpress 使用“cron 锁”defined('DOING_CRON') 并在调用 spawn_cron 方法时设置瞬态 $lock = get_transient('doing_cron')

因此,如果您查看wp-includes/cron.php,您会看到默认情况下 Wordpress crons 不会同时运行,并且不会每 60 秒运行一次以上。

// don't run if another process is currently running it or more than once every 60 sec.
    if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time )
        return;

【讨论】:

有趣!所以基本上如果我更改 cron.php 代码,我应该能够同时触发 cron 作业。我确实使用了一个 cron 管理插件,它确实显示所有 cron 作业都在运行(尽管实际上只有一个在运行) 我相信是的,我最初的想法是克隆 WP 的本地 cron 方法并对其进行一些修改:)【参考方案2】:

如果您一次只能发送一两封电子邮件,这将很难解决。解决此问题的更简单方法可能是让 WordPress 使用 SMTP 电子邮件服务器,该服务器允许您需要发送的电子邮件频率。只需在您当前的托管服务提供商上添加一个新的电子邮件帐户就足够了。如果您不知道如何手动设置,有一些插件可以为您完成。

【讨论】:

感谢您的回复....代码中的“2 封电子邮件阈值”只是一个示例...阈值是每 5 分钟大约 20 封电子邮件....是的当然是可以使用允许更高频率发送电子邮件的其他 SMTP 服务器....但这只是在避免问题...我主要是想知道 wordpress cron 的行为方式,并且我将电子邮件问题用作研究案例。 嗨!抱歉,如果您认为我回避了您的问题。如果您有太多注册,以至于您必须查询电子邮件,那么您也应该有如此多的访问,以至于您可以依靠 wp-cron 或多或少地不断运行。我只需设置一个 cron 作业以每分钟运行一次,然后选择 2 封最近的电子邮件,发送它们,然后在它们上设置一个标志以指示它们已发送。当然,如果您有几个小时没有访问您的网站,那么电子邮件可能会延迟。但是,如果您使用 wp cron,任何类型的队列都会出现这种情况。【参考方案3】:

由于 php 是从上到下运行的,所以当你使用 wordpress 调度事件函数来调度事件时,如下所示:

if (! wp_next_scheduled ( 'my_hourly_event' )) 
    wp_schedule_event(time(), 'hourly', 'my_hourly_event');



add_action('my_hourly_event', 'do_this_hourly');

function do_this_hourly() 
    // do something every hour

这个函数do_this_hourly()会按计划运行,但是你在这个函数里面写的代码只会一个接一个地运行。

    我们以邮件发送给 5 个人为例,邮件会一个一个循环发送给他们。 时间戳是由您使用的插入查询输入的,timestampmail sent time 之间没有连接,这个时间戳是您为自己的日志创建的,以便您检查。

肯定会有一些差异,即 10 秒,也可以更小或更大,具体取决于服务器发送电子邮件和处理插入查询所花费的时间。

每个查询都会被触发,时间戳会根据当时的时间(服务器时间)插入。

【讨论】:

以上是关于wordpress cron 作业是顺序执行还是并行执行?的主要内容,如果未能解决你的问题,请参考以下文章

Wordpress Cron作业未运行

登录的用户 id 没有进入 wordpress cron 作业

PHP Wordpress - 禁用Cron作业功能

php 在wordpress中创建一个cron作业

如何每 72 分钟执行一次 cron 任务

cron 作业不工作