【发布时间】:2016-02-08 19:49:53
【问题描述】:
我在谷歌上告诉我的所有事情都应该不发生,但它确实发生了。
我正在构建一个迁移工具来构建一个“主数据库”。我有一个管理面板,只有少数选定的人可以访问。有一个合并按钮,用于启动 AJAX 调用以运行迁移 php 函数。考虑到我仍在开发它,我不确定这个脚本需要多长时间,但我预计一旦推送到生产环境并填充生产数据库至少需要 20 分钟。我不需要关于最佳实践的讲座告诉我不要通过 GUI 来做。这也将成为一个 cron,但是如果管理员愿意,我希望能够手动诱导它。
这是我的流程。迁移功能立即关闭会话session_write_close() 允许我同时运行多个 php 脚本。我这样做是因为我启动了一个 setInterval 来检查会话变量。这是我的“进度”,它只是我正在进行的循环迭代的一个整数。在我的迁移脚本中,我打开会话,将 1 添加到该 int,然后再次关闭会话。我在每个循环结束时执行此操作。
通过这样做,我成功地为我的 AJAX 创建了一个进度。现在我注意到了一些事情。如果我开始迁移,请关闭我的选项卡 - 或刷新。一旦我重新加载页面,我的进度就会继续增长。这告诉我迁移脚本仍在后台执行。
如果我 100% 关闭浏览器,或清除会话,我将不再看到进度上升。然而,这并不是因为脚本停止了。这是因为我的进度指示依赖于会话,一旦我清除会话或关闭浏览器,我的会话 cookie 就会更改。但是我知道脚本仍在运行,因为我可以手动查询数据库并查看正在添加的条目。
现在回答我的问题: 我不想要这个。如果我的浏览器关闭,如果我按下刷新,如果我失去连接等,我希望脚本被终止。我希望它停止中间进程。
我试过 ignore_user_abort(false);但是我很确定这是特定于命令行的,对我没有任何影响。
我希望终止它,因为我正在构建一个“进度恢复”功能,我们可以在其中选择再次恢复迁移进度的位置。
有什么建议吗?
更新:
我不想走这条路,但我想的一些解决方案是我可以有另一个会话变量。这是我的“最后一次验证客户”,这可能是一个时间戳。在我的 javascript 中,在客户端,每隔 30 秒我就可以点击一个 php 脚本来“更新上次验证客户端时”。例如,在每个循环开始时的迁移函数中,我可以检查以确保时间戳不像 60 秒旧。如果它是 60 秒或更早,我会做一个 die 从而停止我的脚本。这在本地意味着“如果没有客户端更新此时间戳,那么我们可以假设用户关闭了他的浏览器/选项卡/刷新”。至于功能,我可以在命令行(cron)中忽略此检查。不是理想的解决方案,但这是我的计划 B
【问题讨论】:
-
这实际上是不可能做到的——无论如何也不容易。一旦执行 PHP 脚本,它就会一直运行,直到它停止或被您告知停止。关闭浏览器选项卡并不足以做到这一点。您可以中止 AJAX 调用,但这是不同的,仍然无法实现您希望实现的目标。
-
将迁移过程分成许多较小的步骤。编写一个管理器并轮询进程并让它接收开始/停止/重启命令。
-
@dgig 事实并非如此,相反。如果客户端断开连接,php 脚本的执行将立即终止,如果 php 在 http 服务器环境中用作模块,这是通常的情况。如果使用另一种方法,例如 cgi 或 fastcgi,那确实是不同的。这就是为什么函数
ignore_client_abort()存在的原因,实际上...... -
会不会其实不是php脚本还在执行,而是数据库服务器还在处理?
标签: php ajax execute continuous