在发送HTTP响应后继续执行PHP代码。
在发送HTTP响应后继续执行PHP代码。
如何让以Apache mod_php形式运行的PHP 5.2将完整的HTTP响应发送给客户端,然后再执行1分钟的操作?
长话短说:
我有一个PHP脚本,需要执行一些长时间的数据库请求和发送电子邮件,运行时间为45到60秒。这个脚本是由我无法控制的应用程序调用的。我需要应用程序报告从PHP脚本接收到的任何错误消息(主要是无效参数错误)。
应用程序的超时延迟短于45秒(我不知道确切的值),因此将每次执行PHP脚本都记录为错误。因此,我需要PHP尽快将完整的HTTP响应发送给客户端(理想情况下,一旦输入参数验证完成),然后运行数据库和电子邮件处理。
我正在运行mod_php,因此pcntl_fork不可用。我可以通过将要处理的数据保存到数据库并从cron运行实际进程来解决这个问题,但我正在寻找一个更简洁的解决方案。
在处理初始请求的脚本中创建一个处理队列的条目,然后立即返回。然后,创建一个单独的进程(可能通过cron)定期运行队列中待处理的工作。
这是我最初想到的解决方案。另一方面,为了解决第三方应用程序的超时问题而设置一个处理队列,让我感到有些不安。
这种解决方案缺乏并行性...或者需要启动一个工作进程池来处理队列。我最终选择了将http请求发布并断开与自己本地主机的连接(根据SomeGuy在这里描述的方式),以利用现有的httpd工作进程池作为后台处理程序。
在处理初始请求的脚本中创建一个处理队列的条目,然后立即返回。然后,创建一个单独的进程(可能通过cron)定期运行队列中待处理的工作。
这是我最初想到的解决方案。另一方面,为了解决第三方应用程序的超时问题而设置一个处理队列,让我感到有些不安。
这种解决方案缺乏并行性...或者需要启动一个工作进程池来处理队列。我最终选择了将http请求发布并断开与自己本地主机的连接(根据SomeGuy在这里描述的方式),以利用现有的httpd工作进程池作为后台处理程序。
在这段代码中,我们可以看到作者想要在发送HTTP响应后继续执行PHP代码。作者的意图是在接收到银行支付成功的请求后,调用各种服务并处理大量数据,这可能需要超过10秒的时间,但银行的链接具有固定的超时期限。因此,作者在接收到请求后立即向银行发送响应,并在银行离开后继续处理数据。
代码中的
<?php
ob_end_clean();
header("Connection: close");
ignore_user_abort(); // optional
ob_start();
echo ('Text the user will see');
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush(); // Strange behaviour, will not work
flush(); // Unless both are called !
session_write_close(); // Added a line suggested in the comment
// Do processing here
sleep(30);
echo('Text user will never see');
?>
然而,有几个问题导致代码无法正常工作。首先,ob_end_flush()
函数的行为与预期不符,需要将其与flush()
函数一起调用才能正常工作。其次,如果使用会话(session),则需要在flush()
之后添加session_write_close()
,否则在后台处理完成之前无法在同一浏览器选项卡中使用网站。最后,如果代码在像Varnish这样的代理服务器后运行,该解决方案将无效。
根据评论中的建议,我们可以对代码进行以下修改来解决上述问题:
<?php
ob_end_clean();
header("Connection: close");
ignore_user_abort(true); // optional
ob_start();
echo ('Text the user will see');
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush(); // Strange behaviour, will not work
flush(); // Unless both are called !
session_write_close(); // Added a line suggested in the comment
// Do processing here
sleep(30);
echo('Text user will never see');
?>
以上修改可以解决在一些情况下代码无法正常工作的问题。