GearmanClient::addTaskBackground

(PECL gearman >= 0.5.0)

GearmanClient::addTaskBackgroundAñade una tarea de fondo para su ejecución en paralelo

Descripción

public GearmanClient::addTaskBackground(
    string $function_name,
    string|int|float $workload,
    mixed $context = null,
    ?string $unique_key = null
): GearmanTask|false

Añade una tarea de fondo para su ejecución en paralelo con otras tareas. Llámese a este método para todas las tareas que deban ejecutarse en paralelo, y luego, llámese al método GearmanClient::runTasks() para realizar las tareas.

Parámetros

function_name

Función registrada que ejecutará el worker

workload

Datos serializados a ser procesados

context

Aplicación context a asociar con la tarea

unique_key

ID único para identificar una tarea en particular

Valores devueltos

Un objeto GearmanTask o false si la tarea no pudo ser añadida.

Ejemplos

Ejemplo #1 2 tareas, una de ellas en segundo plano

Este ejemplo muestra la diferencia entre la ejecución en segundo plano y una ejecución normal. El cliente añade 2 tareas que deben ejecutar la misma función, pero una ha sido añadida con el método addTaskBackground(). Se define una función de retorno para monitorear el progreso del trabajo. Un agente simple con un retraso artificial reporta el progreso y el cliente lo procesa mediante la función de retorno. Se ejecutan 2 agentes en este ejemplo. Obsérvese que la tarea en segundo plano no es mostrada por el cliente.

<?php

# El script del cliente

# Crea un cliente Gearman
$gmc= new GearmanClient();

# Añade un servidor de trabajos por omisión
$gmc->addServer();

# Define 2 funciones de retorno para monitorear el progreso
$gmc->setCompleteCallback("reverse_complete");
$gmc->setStatusCallback("reverse_status");

# Añade una tarea para la función "reverse"
$task= $gmc->addTask("reverse", "Hello World!", null, "1");

# Añade otra tarea, pero esta vez, en segundo plano
$task= $gmc->addTaskBackground("reverse", "!dlroW olleH", null, "2");

if (!
$gmc->runTasks())
{
echo
"ERROR " . $gmc->error() . "\n";
exit;
}

echo
"HECHO\n";

function
reverse_status($task)
{
echo
"ESTADO : " . $task->unique() . ", " . $task->jobHandle() . " - " . $task->taskNumerator() .
"/" . $task->taskDenominator() . "\n";
}

function
reverse_complete($task)
{
echo
"TERMINADO : " . $task->unique() . ", " . $task->data() . "\n";
}

?>
<?php

# El script del agente

echo "Inicio\n";

# Crea un agente.
$gmworker= new GearmanWorker();

# Añade un servidor por omisión (localhost).
$gmworker->addServer();

# Registra la función "reverse" en este servidor.
$gmworker->addFunction("reverse", "reverse_fn");

print
"Esperando trabajo...\n";
while(
$gmworker->work())
{
if (
$gmworker->returnCode() != GEARMAN_SUCCESS)
{
echo
"return_code: " . $gmworker->returnCode() . "\n";
break;
}
}

function
reverse_fn($job)
{
echo
"Trabajo recibido : " . $job->handle() . "\n";

$workload = $job->workload();
$workload_size = $job->workloadSize();

echo
"Carga del agente : $workload ($workload_size)\n";

# Este ciclo no es necesario, pero ayuda a entender el funcionamiento
for ($x= 0; $x < $workload_size; $x++)
{
echo
"Enviando estado : " . ($x + 1) . "/$workload_size complete\n";
$job->sendStatus($x+1, $workload_size);
$job->sendData(substr($workload, $x, 1));
sleep(1);
}

$result= strrev($workload);
echo
"Resultado : $result\n";

# Se devuelve al cliente lo que se desee.
return $result;
}

?>

El agente muestra, para los 2 trabajos :

Trabajo recibido : H:foo.local:65
Carga del agente : !dlroW olleH (12)
1/12 complete
Trabajo recibido : H:foo.local:66
Carga del agente : Hello World! (12)
Enviando estado : 1/12 complete
Enviando estado : 2/12 complete
Enviando estado : 2/12 complete
Enviando estado : 3/12 complete
Enviando estado : 3/12 complete
Enviando estado : 4/12 complete
Enviando estado : 4/12 complete
Enviando estado : 5/12 complete
Enviando estado : 5/12 complete
Enviando estado : 6/12 complete
Enviando estado : 6/12 complete
Enviando estado : 7/12 complete
Enviando estado : 7/12 complete
Enviando estado : 8/12 complete
Enviando estado : 8/12 complete
Enviando estado : 9/12 complete
Enviando estado : 9/12 complete
Enviando estado : 10/12 complete
Enviando estado : 10/12 complete
Enviando estado : 11/12 complete
Enviando estado : 11/12 complete
Enviando estado : 12/12 complete
Enviando estado : 12/12 complete
Resultado : !dlroW olleH
Resultado : Hello World!

Salida del cliente :

ESTADO : 1, H:foo.local:66 - 1/12
ESTADO : 1, H:foo.local:66 - 2/12
ESTADO : 1, H:foo.local:66 - 3/12
ESTADO : 1, H:foo.local:66 - 4/12
ESTADO : 1, H:foo.local:66 - 5/12
ESTADO : 1, H:foo.local:66 - 6/12
ESTADO : 1, H:foo.local:66 - 7/12
ESTADO : 1, H:foo.local:66 - 8/12
ESTADO : 1, H:foo.local:66 - 9/12
ESTADO : 1, H:foo.local:66 - 10/12
ESTADO : 1, H:foo.local:66 - 11/12
ESTADO : 1, H:foo.local:66 - 12/12
TERMINADO : 1, !dlroW olleH
HECHO

Ver también

add a note

User Contributed Notes 3 notes

up
16
Anonymous
9 years ago
It is unlikely this example works quite as advertised.

The foreground job will block, however the background job should not.. (and if it does that's not documented Gearman behaviour far as I know and would not make sense for a Background job).

So, if the foreground job completes, then we would expect runTasks() to return at that moment, regardless of the status of the background job(s). With nothing else to do, the php script (the client) in this example would exit at that point.

To fully-utilize background jobs, it's reasonable to assume that we still wish to know their status. To do that, you need a polling loop that "checks up on them" and waits until their completion.

That eliminates the point of background jobs of course - because the client would still be Blocking (in a polling loop) more or less occupied, and unable to exit/finish.

So, in practice, background jobs mean you are decoupled from the client upon execution (because the main point is to free up the client, otherwise just use foreground execution), which means the client is likely going to exit, meaning the jobs themselves should be reporting their status and final result independently, not leaving it up to the client.

It's a significantly different setup compared to foreground jobs. In fact this example is kind of silly to even mix the two.

Nobody will ever see this post, because apparently nobody in the world has ever commented on the php gearman client, but it's a good post never the less.
up
2
iunknowvb at gmail dot com
7 years ago
function run_process($cmd,$outputFile = '/dev/null', $append = false){
$pid=0;
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
$cmd = 'wmic process call create "'.$cmd.'" | find "ProcessId"';
$handle = popen("start /B ". $cmd, "r");
$read = fread($handle, 200); //Read the output
$pid=substr($read,strpos($read,'=')+1);
$pid=substr($pid,0,strpos($pid,';') );
$pid = (int)$pid;
pclose($handle); //Close
}else{
$pid = (int)shell_exec(sprintf('%s %s %s 2>&1 & echo $!', $cmd, ($append) ? '>>' : '>', $outputFile));
}
return $pid;
}
function is_process_running($pid){
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
//tasklist /FI "PID eq 6480"
$result = shell_exec('tasklist /FI "PID eq '.$pid.'"' );
if (count(preg_split("/\n/", $result)) > 0 && !preg_match('/No tasks/', $result)) {
return true;
}
}else{
$result = shell_exec(sprintf('ps %d 2>&1', $pid));
if (count(preg_split("/\n/", $result)) > 2 && !preg_match('/ERROR: Process ID out of range/', $result)) {
return true;
}
}
return false;
}
function stop_process($pid){
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
$result = shell_exec('taskkill /PID '.$pid );
if (count(preg_split("/\n/", $result)) > 0 && !preg_match('/No tasks/', $result)) {
return true;
}
}else{
$result = shell_exec(sprintf('kill %d 2>&1', $pid));
if (!preg_match('/No such process/', $result)) {
return true;
}
}
}
$cmd='';
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
$cmd= $php_path.'\php.exe '.$path.'\long_process.php' ;
}else{
$cmd='/usr/bin/php -f /var/www/example.com/public/long_process.php';
}

$pid=run_process($cmd);
up
-2
raitech at gmail dot com
9 years ago
This method seems only useful when you doesn't need to know something about the worker, when you can let runTasks() finishes its code and destroy the GearmanClient object without a problem.

If you need to get data from worker via callbacks, forget it after runTasks() finishes.

You have to block your execution in the GearmanClient "main loop", so it can call the callbacks. It seems that runTasks() is that "main loop".
To Top