Gearman обрабатывает параллельно и дает промежуточный вывод

Я использую Gearman и Slim PHP для создания спокойного API, в котором:

Пользователь вызовет restful API и отправит URL-адрес файла. Тогда это будет:

  1. Загрузите файл и отправьте пользователю уникальный идентификатор файла в качестве http-ответа.
  2. По мере отправки ответа я хочу начать обработку файла
  3. Пользователь может проверить статус процесса с помощью вызова API GET www.example.com/api/status.

Я использовал gearman для doNormal для части загрузки файла, но ответ о статусе отправляется только после завершения обработки. Кроме того, как получить статус каждого клиентского процесса? Мне нужна дополнительная помощь о том, как именно я могу структурировать то же самое, и несколько подробностей о постановке в очередь обработки, поскольку я новичок в Gearman.


person Hardik Dave    schedule 18.08.2015    source источник


Ответы (1)


Вам нужно использовать jobstatus и doBackground(). Во-первых, вам нужно инициализировать передачу. Это делается путем отправки задачи в фоновый режим и отправки пользователю дескриптора задания. Вы вызываете это через yourserver.com/api/file-transfer и должны отправить запрос POST с установленным fileurl. Ответ - объект json.

<?php
// use composer for slim
require_once "vendor/autoload.php"; 
$app = new \Slim\Slim();

// init file transfer
$app->post('/file-transfer', function () use ($app) {
    $resp = array();
    try {
        // get file url
        $fileurl = $app->request->post('fileurl');
        $data = json_encode(array("fileurl"=>$fileurl);

        // send to gearman
        $client = new GearmanClient();
        $client->addServer();

        // store the gearman handle and send the task to the background
        $jobHandle = $client->doBackground("fileUpload", $data);

        if ($client->returnCode() != GEARMAN_SUCCESS) throw new Exception("Could not add the job to the queue.", 1);

        $resp["msg"] = "File upload queued";
        $resp["handle"] = $jobHandle;
    } catch(Exception $e) {
        // some error handling
        $resp["msg"] = "There occured a strange error.";
        $resp["error"] = true;
    } finally {
        $response = $app->response();
        $response['Content-Type'] = 'application/json';
        $response->status(200);
        $response->body(json_encode($resp));    
    }
});
?>

На втором этапе пользователю необходимо запросить сервер с дескриптором задания (который он получил от первого вызова):

$app->post('/file-status', function () use ($app) {
    $jobHandle = $app->request->params('handle');
    $resp = array();
    try {
        // ask for job status
        $client = new GearmanClient();
        $client->addServer();
        $stat = $client->jobStatus($jobHandle);
        if (!$stat[0]) { // it is done
            $resp["msg"]    = "Transfer completed.";
        } else {
            $resp["msg"]    = "Transfer in progress.";
            $w = (float)$stat[2]; // calculate the percentage
            $g = (float)$stat[3];
            $p = ($g>0)?$w/g*100:0;
            $resp["percentage"] = $p;
        }
    } catch(Exception $e) {
            // some error handling
            $resp["msg"] = "There occured a strange error.";
            $resp["error"] = true;
    } finally {
        $response = $app->response();
        $response['Content-Type'] = 'application/json';
        $response->status(200);
        $response->body(json_encode($resp));    
    }
});

Во втором запросе у вас есть массив $stats из $client->jobStatus(). $stats[0] сообщает вам, известно ли задание серверу gearman. Второй элемент проверяет, работает ли он, и три и четыре (2/3) используются для расчета процента перевода (эти значения нужно установить самостоятельно!).

person Jan    schedule 18.08.2015
comment
Да, некоторый код действительно был бы полезен. Я не могу отправить ответ, а затем продолжить процесс после него - person Hardik Dave; 18.08.2015
comment
Я понимаю, однако, я хочу повторить ответ пользователю после завершения загрузки файла. Затем запустите новый процесс (для обработки загруженного файла), для которого я хочу показать пользователю статус. Статус не должен быть для API загрузки файлов. - person Hardik Dave; 19.08.2015
comment
К сожалению, обратные вызовы не работают для фоновых заданий в Gearman. Таким образом, возможным решением было бы использовать jquery ajax и опрашивать сервер каждые пять-десять. секунд до завершения обработки. - person Jan; 19.08.2015