不幸的是,您几乎肯定无法以所希望的方式解决问题。当客户端在接收请求之前关闭连接时发送的FastCGI信号为FCGI_ABORT_REQUEST。
当HTTP客户端在代表该客户端运行的FastCGI请求正在运行时关闭其传输连接时,Web服务器会中止FastCGI请求。这种情况可能看起来不太可能发生;大多数FastCGI请求将具有短的响应时间,如果客户端较慢,则Web服务器会提供输出缓冲区。但是,FastCGI应用程序可能会延迟与另一系统通信或执行服务器推送。
不幸的是,看起来原始的FastCGI实现和PHP-FPM都不支持FCGI_ABORT_REQUEST信号,因此无法被中断。
好消息是有更好的解决方法。基本上,您永远不应该处理需要很长时间才能完成的请求。相反,如果请求需要很长时间来处理,则应:
- 将其推入需要处理的任务队列中。
- 向客户端返回“任务ID”。
- 让客户端定期轮询以查看是否已完成该“任务”,并在完成时显示结果。
除了这三个基本事项之外,如果您担心在客户端不再对请求结果感兴趣时浪费系统资源,还应添加:
- 将任务分解为小的工作单元,仅在客户端仍在请求结果时将任务从一个工作“状态”移动到下一个工作“状态”。
您没有说明长时间运行的任务是什么 - 让我们假设它是从另一台服务器下载大型图像文件,操纵该图像,然后将其存储在S3中。因此,此任务的状态将类似于:
TASK_STATE_QUEUED
TASK_STATE_DOWNLOADING //Moves to next state when finished download
TASK_STATE_DOWNLOADED
TASK_STATE_PROCESSING //Moves to next state when processing finished
TASK_STATE_PROCESSED
TASK_STATE_UPLOADING_TO_S3 //Moves to next state when uploaded
TASK_STATE_FINISHED
因此,当客户端发送初始请求时,它会收到一个任务ID,并且当查询该任务的状态时,可能:
或者
- 如果它处于以下某种状态之一,则客户端请求将其推进到下一个状态。
即
TASK_STATE_QUEUED => TASK_STATE_DOWNLOADING
TASK_STATE_DOWNLOADED => TASK_STATE_PROCESSING
TASK_STATE_PROCESSED => TASK_STATE_UPLOADING_TO_S3
因此,只有客户端感兴趣的请求才会继续处理。
顺便说一句,我强烈建议使用专门设计用于高效工作的队列来存储任务队列(例如Rabbitmq、Redis或Gearman),而不仅仅是使用MySQL或任何数据库。基本上,SQL在充当队列时并不是那么出色,您最好从一开始就使用适当的技术,而不是从错误的技术开始,然后在数据库在试图进行数百次插入和更新每秒以管理任务时超载时,在紧急情况下进行更换。
作为附带好处,通过将长时间运行的过程分解成任务,可以轻松地实现以下目标:
- 查看处理时间花费在哪些步骤上。
- 查看和检测处理时间的波动(例如,如果CPU达到100%利用率,则图像调整大小将突然需要更长的时间)。
- 向速度慢的步骤投入更多资源。
- 您可以向客户端提供状态更新消息,以便他们可以看到任务的进度,这比它只是“无所事事”更好的用户体验。
$buffersize=256; echo str_repeat(" ", $buffersize); flush();
请参见 issue#115 或者使用echo
和 ob_implicit_flush。 - pce