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

lex*_*eme 6 php windows asynchronous publish-subscribe

考虑下图:

工作流程

思念

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

问题

  1. 那么客户端 - 服务器通信的哪种方法最适合从这些子进程发送回客户端的通知?
  2. 什么是创建子进程的最佳方法?我已经读到了proc_open,curl方法.我没有得到如何使用消息队列(如果它适用的话).

笔记

只是告诉我我正在使用Windows OS(Windows Server 2008)和XAMPP

Aby*_*Aby 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计时器可以采取进一步的操作吗?

希望这可以帮助.


cre*_*lem 4

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

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

客户端现在可以轻松地通过用户 ID 询问任务表来检查待处理的任务。如果状态已完成或出现错误,您可以向用户提供良好的反馈。您可以每五秒轮询一次此信息。间隔时间取决于您的需要。对于您的浏览器来说,不到五秒的轮询可能会很奇怪。最好由客户端获取状态,而不是服务器将状态发送给客户端。如果服务器发送状态很重要,则必须使用网络套接字。后端可以是相同的。

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

setInterval(function(){
    $.ajax({ url: "server", success: function(data){
        //Update your dashboard gauge
        salesGauge.setValue(data.value);
    }, dataType: "json"});
}, 30000);
Run Code Online (Sandbox Code Playgroud)

仅当您有一些高级选项时,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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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