异步运行 PHP 任务

2022-08-30 06:45:08

我处理一个有点大的Web应用程序,后端主要是PHP。代码中有几个地方我需要完成一些任务,但我不想让用户等待结果。例如,在创建新帐户时,我需要向他们发送欢迎电子邮件。但是当他们点击“完成注册”按钮时,我不想让他们等到电子邮件实际发送,我只想开始该过程,并立即向用户返回消息。

到目前为止,在某些地方,我一直在使用exec()的黑客攻击。基本上做这样的事情:

exec("doTask.php $arg1 $arg2 $arg3 >/dev/null 2>&1 &");

这似乎有效,但我想知道是否有更好的方法。我正在考虑编写一个系统,该系统将MySQL表中的任务排入队列,以及一个单独的长时间运行的PHP脚本,该脚本每秒查询该表一次,并执行它找到的任何新任务。这还具有这样一个优点,即如果我将来需要,可以在几台工作机器之间拆分任务。

我是否在重新发明轮子?有没有比exec()黑客或MySQL队列更好的解决方案?


答案 1

我使用了排队方法,它运行良好,因为您可以将该处理推迟到服务器负载空闲,如果您可以轻松地分区“不紧急的任务”,则可以非常有效地管理负载。

滚动自己的不是太棘手,这里有一些其他选项可以查看:

  • GearMan - 这个答案写于2009年,从那时起,GearMan看起来是一个受欢迎的选择,请参阅下面的评论。
  • ActiveMQ,如果你想要一个完整的开源消息队列。
  • ZeroMQ - 这是一个非常酷的套接字库,它可以很容易地编写分布式代码,而不必太担心套接字编程本身。你可以将它用于单个主机上的消息队列 - 你只需让 Webapp 将某些内容推送到一个队列中,持续运行的控制台应用将在下一个合适的机会使用该队列。
  • 豆茎 - 在写这个答案时才找到这个,但看起来很有趣
  • dropr 是一个基于 PHP 的消息队列项目,但自 2010 年 9 月以来一直没有得到积极维护
  • php-enqueue是最近(2017年)围绕各种队列系统维护的包装器。
  • 最后,一篇关于使用 memcached 进行消息队列的博客文章

另一种可能更简单的方法是使用ignore_user_abort - 一旦您将页面发送给用户,您就可以进行最终处理而不必担心过早终止,尽管这确实具有从用户角度延长页面加载的效果。


答案 2

当您只想执行一个或多个HTTP请求而不必等待响应时,还有一个简单的PHP解决方案。

在调用脚本中:

$socketcon = fsockopen($host, 80, $errno, $errstr, 10);
if($socketcon) {   
   $socketdata = "GET $remote_house/script.php?parameters=... HTTP 1.1\r\nHost: $host\r\nConnection: Close\r\n\r\n";      
   fwrite($socketcon, $socketdata); 
   fclose($socketcon);
}
// repeat this with different parameters as often as you like

在被调用的脚本.php,您可以在第一行调用这些 PHP 函数:

ignore_user_abort(true);
set_time_limit(0);

这会导致脚本在 HTTP 连接关闭时继续运行,没有时间限制。


推荐