Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to notify user when async task ends in PHP/ Windows

Consider the diagram below:

the workflow

thoughts

  1. user can perform single file/batch upload (I know about HTTP specification), by batch I mean that somebody visually is able to send multiple files at a time.
  2. image uploading service is meant to create a child process (of image processor) per file sent.

questions

  1. then what approach of client-server communication is the best suitable to send notifications from those child processes back to the client?
  2. what's the best approach to create a child process? I've read about proc_open, curl approaches. I didn't get how to use message queues (if it is applicable at all).

notes

just got to tell that I'm using Windows OS (Windows Server 2008) and XAMPP

like image 960
lexeme Avatar asked Nov 15 '13 13:11

lexeme


3 Answers

in ASP.NET it is easily doable. Here is an example of it implemented in ASP.NET. http://brockallen.com/2013/07/27/implementing-async-http-modules-in-asp-net-using-tpls-task-api/

But since you want it to be done in PHP/windows, you can get it done via few ways.

Why can't you make the imageprocessing, when complete, update some field in a database table or the session, and from your HTML page, keep a javascript timer, which polls the database/session variable of the possible status ? Once it gets a completed status from the db/session (which was updated by the image processing logic), your javascript timer can take further actions ?

Hope this helps.

like image 96
Aby Avatar answered Nov 14 '22 23:11

Aby


The User Uploads the image. After this step you can create a Task. One Taks is one row at the task table in your database.

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();
        }
    }
}

At the server side you've to think how to work / organize your tasks. This depends on your needs. With the power of a TaskManager you can control your process. This is very important that not 100 process are running parallel.

The Client-Side can now easy ask the task table with the userid to check for pending task. If the status finished or error you can give the user an excellent feedback. You can poll this information every five seconds. The interval depends on your need. A polling under five seconds can be odd for your browser. Its a good idea that the client will fetch the status instead of the server will send the status to the client. If it is important that the server sends the status you've to use web sockets. The backend can be the same.

Here is a simple polling example.

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

proc_open is only good if you've have some advanced options. With the power of proc_open (have a eye on the pipes) and in combination with stream_set_blocking. You can Write an async task handling. If you don't need some special exec will be enough.

Here is a non-blocking example.

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;
    }
}

I hope this will gave you some inspiration to solve your problem. For real message queues you can use what you want. I'm a fan of http://kr.github.io/beanstalkd/ I'll now stop with solutions and ideas cuz, this issue is more complex and I can write another 100 pages. If you've konkrete questions, you can drop a line.

like image 44
createproblem Avatar answered Nov 14 '22 23:11

createproblem


For a proper client-server communication in a file upload process, we normally use AJAX (Async JS) in jQuery. Send whatever required data which in your case would be the file details. Perform operations on the server(PHP) and when done send json response back to client for notification purposes. The catch is, you need to get your child process's response in the success function of the AJAX. Only after the successful completion will the notifications arrive.

like image 21
Makrand Avatar answered Nov 14 '22 23:11

Makrand