【问题标题】:php asynchronous call and getting response from the background jobphp异步调用并从后台作业获取响应
【发布时间】:2010-01-29 10:16:34
【问题描述】:

我对这个主题进行了一些谷歌搜索,但找不到我的问题的答案。

我想要达到的目标如下:

  1. 客户端对服务器中的函数进行异步调用
  2. 服务器在后台运行该函数(因为该函数很耗时),同时客户端没有挂起
  3. 客户端不断调用服务器请求后台作业的状态

你能给我一些解决我问题的建议吗?

非常感谢! ^-^

【问题讨论】:

    标签: php asynchronous background response progress


    【解决方案1】:

    您没有指定异步调用的语言,但我假设两端都使用 PHP。 我认为最优雅的方式是:

    • HTML 页面加载,为操作定义一个随机键(例如,使用 rand() 或已经可用的会话 ID [请注意,虽然同一用户可能会启动两个操作])

      李>
    • HTML 页面使 Ajax 调用 PHP 脚本到 start_process.php

    • start_process.php执行exec /path/to/scriptname.php启动进程;有关如何在后台启动进程的建议,请参阅User Contributed Notes on exec()。哪一个适合您,主要取决于您的操作系统。

    • long_process.php 经常将其状态写入状态文件,以您的 Ajax 页面生成的随机密钥命名

    • HTML 页面频繁调用show_status.php,读取状态文件并返回进度。

    【讨论】:

    • 如果您想要一个由会话创建的进程的唯一标识符,那么比 rand() 更安全、更明显的候选者将是会话 ID。此外,贡献注释中引用的代码将在非 Microsoft 系统上以不可预知的方式失败。
    【解决方案2】:

    有一个长期运行的 php 进程的谷歌(请注意,关于该主题有很多不好的建议 - 包括 Pekka 提到的注释 - 这将在 Microsoft 上工作,但在其他任何事情上都会以不可预测的方式失败) .

    您可以开发一个通过套接字响应请求的服务(您的客户端将使用 fsockopen 进行连接) - 实现此目的的一些简单方法是使用 Aleksey Zapparov 的套接字服务器 (http://www.phpclasses.org/browse/package/5758.html),它处理通过以下方式传入的请求但是,由于它作为单个线程运行,因此它可能不太适合需要大量处理的东西。或者,如果您使用的是非 Microsoft 系统,那么您可以将脚本挂在 [x]inetd 上,但是,您需要做一些巧妙的事情来防止它在客户端断开连接时终止。

    要在客户端断开连接后保持运行,PHP 代码必须从独立的 PHP 可执行文件(而不是通过网络服务器)运行 在新进程组中生成一个进程(参见 posix_setsid() 和 pcntl_fork())。为了使客户端能够返回并检查进度,实现此目的的最简单方法是将服务器配置为将其状态写入客户端可以读取的位置。

    C.

    【讨论】:

      【解决方案3】:
      1. Ajax 调用 run 方法 longRunningMethod() 并取回一个标识符(例如一个 id)
      2. 服务器运行该方法,并设置密钥,例如共享内存
      3. 客户端调用 checkTask(id)
      4. 服务器在 sharedmem 中查找密钥并检查就绪状态 [重复 3 和 4 直到 5 完成]
      5. longRunningMethod 已完成,并在 sharedmem 中将状态设置为已完成。

      根据定义,所有 Ajax 调用都是异步的。

      【讨论】:

        【解决方案4】:

        您可以(虽然不是绝对必要的步骤)使用 AJAX 来实例化调用,然后脚本可以创建对共享内存中后台作业状态的引用(甚至是 SQL 表中的临时条目,或者甚至是一个临时文件),以唯一的作业 ID 的形式。

        然后该脚本可以启动您的后台进程并立即将作业 ID 返回给客户端。

        然后客户端可以重复调用服务器(例如通过另一个 AJAX 接口)来查询作业的状态,例如“进行中”、“完成”。

        如果要执行的后台进程本身是用 PHP 编写的(例如,命令行 PHP 脚本),那么您可以将作业 ID 传递给它,它可以向客户端提供有意义的进度更新(通过写入相同的共享内存区域或数据库表)。

        如果要执行的进程本身不是用 PHP 编写的,那么我建议将其包装在命令行 PHP 脚本中,以便它可以监视正在执行的进程何时完成运行(并检查输出以查看是否成功)和适当地更新该任务的状态条目。

        注意:为此使用共享内存是最佳做法,但例如,如果您使用共享主机,则可能不可用。不要忘记你想要清理旧状态条目的方法,所以我会为每个条目存储“started_on”/“completed_on”时间戳值,并让它删除陈旧数据的条目(例如,完成时间戳为超过 X 分钟 - 理想情况下,它还会检查一段时间前开始但从未标记为已完成的作业并发出警报)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-16
          相关资源
          最近更新 更多