1

I have two PHP script (worker and client) to perform tasks in paralell using Gearman.

The server is running properly and the scrips also, if is exectued from the command line of my CentOS 6. The problem comes when I run these scripts from the browser, this response was not returned.

When I run my client script, which in turn needed workers instance, by command line, I get this result:

Got in: 2.04 seconds
string (20) "soidA321esa q alO321"

But if I run it from your web browser, I get this one:

Got in: 0.02 seconds
NULL

I have no idea why it works correctly in one way and not another. Anyone has happened or knows something similar may be happening?

Greetings and thank you.

PS: Attached code involved:

Worker.php

<?php

class GrmWorker
{

    /**
     * Declaración de atributos.
     */
    private $worker;

    /**
     * Constructor de la clase.
     */ 
    public function __construct()
    {
        // Instancia un nuevo Worker.
        $this->worker = new \GearmanWorker();
    }

    /**
     * Añade un servidor de trabajo a una lista de servidores que pueden ser usados para ejecutar trabajos. 
     */
    public function addServer(array $servers = array())
    {
        // Comprueba si se envían los parámetros de servidor o se establecen los predeterminados.
        if (sizeof($servers) == 0)
        {
            $this->worker->addServer('127.0.0.1', '4730');
        }
        else
        {
            // Recorre el array de servidores.
            foreach ($servers as $server)
            {
                // Comprueba que los índices de los parámetros sean correctos.
                if (null !== $server['host'] && null !==$server['port']) 
                {
                    $this->worker->addServer($server['host'], $server['port']);
                }
                else
                {
                    throw new Exception('El array de servidores solo puede contener los índices "host" y "port".');
                }
            }
        }
    }

    /**
     * Registra el nombre de una función en el servidor de trabajos y especifica la llamada de retorno quer corresponde a esa función.
     */
    public function addFunction($functionName, callable $function)
    {
        $this->worker->addFunction($functionName, $function);
    }

    /**
     * Establece el intervalo de tiempo, en milisegundos, en el cual estará disponible el Worker.
     */
    public function setTimeout($miliseconds)
    {
        $this->worker->setTimeout($miliseconds);
    }

    /**
     * Retorna el tiempo actual a esperar, en milisegundos.
     */
    public function timeout()
    {
        $this->worker->timeout();
    }

    /**
     * Pone a funcionar el trabajador.
     */
    public function work()
    {
        while ($this->worker->work());
    }
}

/**
 * Clase que contiene as funciones a declarar para el trabajador.
 */
class Functions
{
    public static function reverse_cb($job)
    {
        sleep(2);

        return strrev('123' . $job->workload());
    }
}

// Instancia un nuevo trabajador.
$worker = new GrmWorker();
$worker->addServer();
$worker->setTimeout(60000);

// Declara las funciones que puede ejecutar el trabajador.
$worker->addFunction("reverse", "Functions::reverse_cb");

// Comienza a trabajar.
$worker->work();

Client.php

<?php

class GrmClient
{
    // Declaración de atributos.
    private $client;
    private $tasks;

    /**
     * Constructor de la clase.
     */
    public function __construct()
    {
        $this->client = new GearmanClient();
        $this->tasks = 0;
    }

    /**
     * Añade un servidor de trabajo a una lista de servidores que pueden ser usados para ejecutar trabajos.
     */
    public function addServer(array $servers = array())
    {
        // Comprueba si se envían los parámetros de servidor o se establecen los predeterminados.
        if (sizeof($servers) == 0)
        {
            $this->client->addServer('127.0.0.1', '4730');
        }
        else
        {
            // Recorre el array de servidores.
            foreach ($servers as $server)
            {
                // Comprueba que los índices de los parámetros sean correctos.
                if (null !== $server['host'] && null !== $server['port']) 
                {
                    $this->client->addServer($server['host'], $server['port']);
                }
                else
                {
                    throw new Exception('El array de servidores solo puede contener los índices "host" y "port".');
                }
            }
        }
    }

    /**
     *  Añade una tarea para ser ejecutada en paralelo.
     */
    public function addTask($function_name, $workload, mixed $context = null)
    {
        $this->client->addTask($function_name, $workload, $context);

        // Aumenta el contador de tareas a ejecutar.
        $this->tasks++;
    }

    /**
     *  Ejecuta una tarea en segundo plano para ser ejecutada en paralelo.
     */
    public function addTaskBackground($function_name, $workload, mixed $context = null)
    {
        $this->client->addTaskBackground($function_name, $workload, $context);

        // Aumenta el contador de tareas a ejecutar.
        $this->tasks++;
    }

    /**
     *  Añade una tarea de alta prioridad para ser ejecutada en paralelo.
     */
    public function addTaskHigh($function_name, $workload, mixed $context = null)
    {
        $this->client->addTaskHigh($function_name, $workload, $context);

        // Aumenta el contador de tareas a ejecutar.
        $this->tasks++;
    }

    /**
     *   Añade una tarea de alta prioridad para ser ejecutada en segundo plano y en paralelo.
     */
    public function addTaskHighBackground($function_name, $workload, mixed $context = null)
    {
        $this->client->addTaskHighBackground($function_name, $workload, $context);

        // Aumenta el contador de tareas a ejecutar.
        $this->tasks++;
    }

    /**
     *  Añade una tarea de baja prioridad para ejecutar en paralelo.
     */
    public function addTaskLow($function_name, $workload, mixed $context = null)
    {
        $this->client->addTaskHigh($function_name, $workload, $context);

        // Aumenta el contador de tareas a ejecutar.
        $this->tasks++;
    }

    /**
     *  Añade una tarea de baja prioridad para ser ejecutada en segundo plano y en paralelo.
     */
    public function addTaskLowBackground($function_name, $workload, mixed $context = null)
    {
        $this->client->addTaskHighBackground($function_name, $workload, $context);

        // Aumenta el contador de tareas a ejecutar.
        $this->tasks++;
    }

    /**
     * Especifica una función a ser llamada cuando se complete una tarea. La función de llamada de retorno acepta un único argumento, un objeto GearmanTask.
     */
    public function setCompleteCallback(callable $function)
    {
        $this->client->setCompleteCallback($function);
    } 

    /**
     * Elimina todas las funciones de retorno de llamada establecidas.
     */
    public function clearCallbacks()
    {
        $this->client->clearCallbacks();
    }

    /**
     * Ejecuta una lista de tareas, previamente establecidas, en paralelo.
     */
    public function runTasks()
    {   
        // Declara el array que contendrá los recursos que manejan los procesos de los workers.
        $process = array();

        // Comprueba si existen suficientes Workers para las tareas solicitadas.
        if ($this->getNumWorkers() < $this->getNumTasks())
        {
            for ($i = 0; $i < $this->getNumTasks() - $this->getNumWorkers(); $i++)
            {
                // Pone en marcha un worker en segundo plano.
                $proce = proc_open("php /var/www/html/web/Worker.php > /dev/null &",
                        array(
                                array("pipe","r"),
                                array("pipe","w"),
                                array("pipe","w")
                        ),
                        $pipes);
                $process[] = $proce;
            }
        }

        // Ejecuta las tareas puestas en cola.
        $this->client->runTasks();

    }

    /**
     * Devuelve el número de tareas definidas.
     */
    public function getNumTasks()
    {
        return $this->tasks;
    }

    /**
     * Devuelve el número de trabajadores activos.
     */
    private function getNumWorkers()
    {
        $workers = shell_exec ("gearadmin --workers");
        $workers = explode(PHP_EOL, $workers);
        return sizeof($workers) - 3;
    }
}

$client = new GrmClient();
$client->addServer();

$result = null;

$client->setCompleteCallback(function(GearmanTask $task) use (&$result)
{
    $result .= $task->data();
});

$client->addTask('reverse', 'Ola q ase');
$client->addTask('reverse', 'Adios');

$start = microtime(true);
$client->runTasks();
$totaltime = number_format(microtime(true) - $start, 2);

echo "Got in: " . $totaltime . " seconds \n";
var_dump($result);
JSGarcia
  • 556
  • 7
  • 18
  • 1
    When called via the browser, the script is much faster, thus presumably not every code has been run. Probably you will have a user with shell access. This user might have permissions (like `proc_open()`) the apache user has not. So check the different permissions with a detailed error messaging (`error_reporting(E_ALL);` and `ini_set('display_errors', 1);`) and see if it throws any errors. – Jan Nov 23 '15 at 12:57
  • **Thanks** @Jan I understand. Once I show errors that occur, I returned the following **error**: *Warning: GearmanClient::runTasks(): send_packet(GEARMAN_COULD_NOT_CONNECT) Failed to send server-options packet -> libgearman/connection.cc:485 in /var/www/html/web/Client.php on line 157* **¿Do you know what is it about?** – JSGarcia Nov 23 '15 at 13:07
  • This occurs when the port (4730) is not set, see [here on SO for more information](http://stackoverflow.com/questions/14883681/gearman-gives-me-gearman-could-not-connect-it-is-definitely-running). – Jan Nov 23 '15 at 14:16
  • Hi @Jan in code, explicitly declare the connection port when adding the server. *addServer('127.0.0.1', '4730')* THX – JSGarcia Nov 23 '15 at 20:25
  • 1
    please accept your own answer and remove "solved ..." – Saic Siquot Nov 24 '15 at 11:50
  • Ok @LuisSiquot, tomorrow accept my own answer and remove solved now – JSGarcia Nov 24 '15 at 11:57

1 Answers1

0

I found the solution, as I thought was unrelated to the code or gearman, supposed to be something of a service configuration. The point is that I have found this debate https://groups.google.com/forum/#!topic/gearman/_dW8SRWAonw and executing the following commands via SHH it worked:

Turned into the MAC Control enforcement Permissive mode.

[root @ localhost share] # getenforce
enforcing
[root @ localhost share] # setenforce 0
[root @ localhost share] # getenforce
permissive

I hope that someone helps.

Community
  • 1
  • 1
JSGarcia
  • 556
  • 7
  • 18
  • 1
    Change the question also for future visitors to something more relevant.I`d do it myself but I have no idea what to call it. – Mihai Nov 24 '15 at 11:04