坏消息是,你几乎肯定无法解决你想解决的问题。客户端在接收请求之前关闭连接时发送的 FastCGI 信号FCGI_ABORT_REQUEST
当 HTTP 客户端在代表 FastCGI 客户端运行 FastCGI 请求时关闭其传输连接时,Web 服务器将中止该请求。这种情况似乎不太可能。大多数 FastCGI 请求的响应时间较短,如果客户端速度较慢,则 Web 服务器会提供输出缓冲。但是 FastCGI 应用程序可能会延迟与另一个系统通信或执行服务器推送。
不幸的是,看起来原始的fast-cgi实现和PHP-FPM都不支持FCGI_ABORT_REQUEST信号,因此无法中断。
好消息是有更好的方法来解决这个问题。基本上,您永远不应该有需要很长时间才能处理的请求。相反,如果请求需要很长时间来处理,您应该:
- 将其推送到需要处理的任务队列。
- 将“任务 ID”返回给客户端。
- 让客户端定期轮询该“任务”是否已完成,并在完成后显示结果。
除了这3件基本的事情 - 如果你担心当客户端不再对请求的结果感兴趣时浪费系统资源,你应该添加:
- 将任务分解为小块工作,并且如果客户端仍在请求结果,则仅将任务从一个工作“状态”移动到下一个工作“状态”。
您不会说出长时间运行的任务是什么 - 让我们假装它是从另一台服务器下载一个大型图像文件,操作该图像,然后将其存储在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
因此,当客户端发送初始请求时,它会返回一个 taskID,然后在查询该任务的状态时,执行以下操作之一:
或
- 如果它处于以下状态之一,则客户端请求会将其提升到下一个状态。
即
TASK_STATE_QUEUED => TASK_STATE_DOWNLOADING
TASK_STATE_DOWNLOADED => TASK_STATE_PROCESSING
TASK_STATE_PROCESSED => TASK_STATE_UPLOADING_TO_S3
因此,只有客户端感兴趣的请求才会继续处理。
顺便说一句,我强烈建议使用一些旨在高性能工作的东西作为队列来保存任务队列(例如Rabbtimq,Redis或Gearman),而不仅仅是使用MySQL或任何数据库。基本上,SQL并不擅长充当队列,您最好从一开始就使用适当的技术,而不是使用错误的技术来启动,然后在数据库过载时必须将其交换出来,当它试图执行数百次插入时,每秒更新只是为了管理任务。
作为附带的好处,通过将长时间运行的流程分解为任务,可以很容易地:
- 查看处理时间的花费位置。
- 查看并检测处理时间的波动(例如,如果 CPUS 达到 100% 利用率,则调整图像大小将突然花费更长的时间)。
- 在缓慢的步骤上投入更多资源。
- 您可以向客户端提供状态更新消息,以便他们可以看到任务的进度,从而提供更好的用户体验,而不是只是坐在那里“无所事事”。