如何在PHP / Windows中异步任务结束时通知用户

时间:2013-11-15 13:17:26

标签: php windows asynchronous publish-subscribe

考虑下图:

the workflow

思想

  1. 用户可以执行单个文件/批量上传(我知道 HTTP 规范), batch 我的意思是有人可以一次发送多个文件。
  2. 图片上传服务旨在为每个发送的文件创建一个子进程(图像处理器)。
  3. 问题

    1. 那么客户端 - 服务器通信的哪种方法最适合将这些子进程的通知发送回客户端?
    2. 创建子进程的最佳方法是什么?我读过有关proc_opencurl方法的文章。我没有得到如何使用消息队列(如果它适用的话)。
    3. 注释

      告诉我我正在使用 Windows操作系统Windows Server 2008)和XAMPP

5 个答案:

答案 0 :(得分:5)

ASP.NET中的

很容易实现。以下是在ASP.NET中实现的示例。 http://brockallen.com/2013/07/27/implementing-async-http-modules-in-asp-net-using-tpls-task-api/

但是既然你想在PHP / windows中完成它,你可以通过几种方式完成它。

为什么不能进行图像处理,完成后,更新数据库表或会话中的某些字段,并从HTML页面保留一个javascript计时器,它会轮询数据库/会话变量的可能状态?一旦它从db / session获得完成状态(由图像处理逻辑更新),你的javascript计时器可以采取进一步的行动吗?

希望这有帮助。

答案 1 :(得分:4)

用户上传图片。完成此步骤后,您可以创建一个任务。 One Taks是数据库中任务表的一行。

class Task
{
    const STATUS_PENDING = 'pending'
    const STATUS_ERROR = 'error'
    const STATUS_FINISHED = 'finished'

    private $userid;
    private $taskData = array();

    public function run()
    {
        // create process
    }

    public function update()
    {
        // update the status an other changes you need to the database
        // or any other storage you use.
    }

    public function getStatus();
}

class TaskManager
{
    const MAX_TASKS = 5;
    private $tasks = array();

    public function addTaks();
    public function start()
    {
        foreach ($tasks as $task) {
            $task->run();
        }
    }
}

在服务器端,您需要考虑如何工作/组织您的任务。这取决于您的需求。借助TaskManager的强大功能,您可以 控制你的过程。这非常重要,不是100个进程并行运行。

客户端现在可以轻松地向用户ID询问任务表以检查待处理任务。如果状态完成或错误,您可以给用户 一个很好的反馈。您可以每五秒轮询一次此信息。间隔取决于您的需要。五秒钟的投票对你来说可能很奇怪 浏览器。一个好主意是客户端将获取状态而不是服务器将状态发送到客户端。如果服务器发送状态非常重要,那么您将使用Web套接字。后端可以是相同的。

这是一个简单的轮询示例。

setInterval(function(){
    $.ajax({ url: "server", success: function(data){
        //Update your dashboard gauge
        salesGauge.setValue(data.value);
    }, dataType: "json"});
}, 30000);
如果您有一些高级选项,

proc_open只会很好。凭借proc_open的力量(关注管道)并结合stream_set_blocking。 您可以编写异步任务处理。如果你不需要一些特殊的exec就足够了。

这是一个非阻塞的例子。

class Task
{
    private $process = null;
    private $pipes = array();
    private $status = 'pending'

    public function run()
    {
        $descriptor = array (
            0 => array("pipe", "r"),
            1 => array("pipe", "w"),
            2 => array("pipe", "w")
        );

        $cmd = "/path/to/progam --with --some-arguments"

        $this->process = proc_open($command, $descriptor, $this->pipes);
        stream_set_blocking($this->pipes[1], 0);
    }

    public function close()
    {
        foreach($this->pipes as $pipe) {
            fclose($pipe);
        }

        $exitStatus = proc_close($this->process);

        $this->process = NULL;

        return $exitStatus;
    }
}

我希望这会给你一些解决问题的灵感。 对于真正的消息队列,您可以使用您想要的。我是http://kr.github.io/beanstalkd/的粉丝我现在停止提供解决方案和想法,因为这个问题 更复杂,我可以再写100页。如果你有konkrete问题,你可以放弃一条线。

答案 2 :(得分:1)

为了在文件上传过程中进行正确的客户端 - 服务器通信,我们通常在jQuery中使用AJAX(Async JS)。  发送您所需的任何所需数据,即文件详细信息。在服务器(PHP)上执行操作,完成后将json响应发送回客户端以进行通知。 问题是,您需要在AJAX的成功函数中获取子进程的响应。只有在成功完成后,通知才会到达。

答案 3 :(得分:1)

您可以查看WAMP

它已有PHPJS个库

Sinse并非所有浏览器都支持您应该小心使用的套接字,或者为旧浏览器提供任何后备支持

答案 4 :(得分:1)

最好的方法是使用消息队列,例如,ActiveMQ,RabbitMQ等。然后将执行以下步骤:

  1. 上传文件到服务器,理想情况下是nginx(PHP很慢,无法有效处理多次上传)。
  2. 调用PHP代码,该代码将准备所有信息并将其作为任务存储到MQ中。还返回浏览器将使用的事件订阅(nginx推送模块)的唯一路径。这可以是WebSocket或长轮询频道,选择一个你熟悉的频道。
  3. PHP守护程序连接到MQ并执行多线程图像处理,将信号发送回nginx推送模块,以通知浏览器任务完成。
  4. 显示用户的通知框并取消订阅推送频道。