如何防止异步进程的等待时间


How do I prevent wait time with an asynchronous process?

我有一个简单的报告脚本,需要5-10分钟才能运行。它是通过在后台运行的fsockopen调用异步触发的。有时候效果很好。但是,如果用户刷新了主页,而由前一个页面加载触发的异步报告仍在运行,主页将挂起,直到第一个页面加载的异步进程完成。

下面是我的脚本背后的粗略逻辑,然后是更多的细节,哪些有效,哪些无效…


main.php

if last report was already run within the hour (mysql select last report time)
    display existing report, that's it.
else
    log latest report process request
    run report asynchronously in the background (async.php)
    notification when updated report is completed (simple ajax pinger every 10s)

async.php

run report
update last report request table with "complete" status
the ajax pinger in main.php pulls the "complete" record and triggers notification

  1. 用户加载main.php

    结果:

    好了。立即加载,记录新的报告请求并按预期触发异步调用。php现在需要5-10分钟来完成报告。

  2. 用户加载main.php 20分钟后(async.php完成后)

    结果:很好,立即加载,但跳过运行异步报告进程,因为它是在最后一个请求的一个小时内。

  3. 用户等待一个小时,再次加载main.php

    结果:都不错,在步骤1

    到目前为止一切都很好,但是…

  4. 现在用户加载main.php只需2分钟后的步骤3。

    结果:

    失败!这个页面加载将挂起,直到步骤3中触发的异步进程完成。尽管包含请求日志时间的mysql表在步骤3中立即更新。因此,步骤4应该简单地跳过调用,只是像步骤2一样渲染现有的报告。

这是怎么回事?您建议如何进行调试?如果另一个用户想在用户1挂在步骤4上时运行相同的报告,那么这个其他用户运行一个新报告就可以了。

我没有在我的代码中做任何奇怪的事情。只是简单的if/then和mysql select查找。异步脚本很大程度上是从外部资源中提取的,所以它不会锁定mysql表,这可能会阻止请求日志时间查找(一个完整的报告可能在10分钟内只运行100个5ms的查询,并且没有一个触及请求日志)。

一种解决方案是只运行进程,但我担心我正在运行许多永远不会看到的报告。而不是只需要5-10分钟的报告,如果我更频繁地运行它们,它会变得指数级大。

那么,坚持我上面的攻击计划(目前),你推荐什么?为什么步骤2可以正确加载,而步骤4不能?是否有某种类型的脚本锁定或限制每个用户我不知道?

问题发生在生成报告的时候,对吗?

如果是这样,您可以在报表开始生成时创建一个文件,并在报表结束时删除它,并在启动新一代报表之前检查它是否存在。在你的async.php文件中:

check if 'running.txt' file exists
if it exists:
    display 'report is already running, you need to wait ! '
    stop
else : 
    create file 'running.txt'
    run report
    delete file 'running.txt'
    update last report request table with "complete" status
    the ajax pinger in main.php pulls the "complete" record and triggers notification

我最终接受了regilero的建议。我设置了一个cron,每分钟运行一次,并从队列中获取任何新请求。这完全消除了延迟问题。谢谢regilero !