Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GearmanJob::setCompleteCallback() not working #3

Closed
vojta opened this issue Jan 24, 2016 · 5 comments
Closed

GearmanJob::setCompleteCallback() not working #3

vojta opened this issue Jan 24, 2016 · 5 comments

Comments

@vojta
Copy link

vojta commented Jan 24, 2016

Hi,

I've just reproduced a problem with setCompleteCallback() on GearmanJob. The callback set by this method is not called on job completion, but setFailCallback is used instead. This is not an issue when using PHP 5.5 gearman extension, it works fine.

gearman_worker.php:

<?php

error_reporting(E_ALL | E_STRICT);

$fRun = function ($task) {

    $taskData = $task->workload();

    try {
        $result = strrev($taskData);
        $task->sendComplete($result);
        $task->sendData($result);
        print PHP_EOL . 'sendComplete done' . PHP_EOL;

    } catch (\Exception $e) {
        print 'Exception caught in worker' . PHP_EOL;
        $str = $e->__toString();
        var_dump($str);
    }

    return GEARMAN_SUCCESS;
};

print "Worker started, pid " . getmypid();

$worker = new GearmanWorker();
$worker->addServer('127.0.0.1', 4730);

//$worker->addFunction('myDefaultMethod', [$worker, 'runTaskX']);
$worker->addFunction('myDefaultMethod', $fRun);

$worker->work();
if ($worker->returnCode() != GEARMAN_SUCCESS) {
    print("return code: " . $worker->returnCode() . PHP_EOL);
} else {
    print 'Worker OK' . PHP_EOL;
}

gearman_client.php:

<?php

error_reporting(E_ALL | E_STRICT);

class BGJobBlob
{
    protected $data, $unique, $method;

    public function __construct($method, $data, $unique)
    {
        $this->data = $data;
        $this->unique = $unique;
        $this->method = $method;
    }

    public function getData()
    {
        return $this->data;
    }

    public function getUniqueID()
    {
        return $this->unique;
    }

    public function getMethod()
    {
        return $this->method;
    }
}

class Client
{
    /**
     * \GearmanClient
     */
    protected $gc;

    public function __construct()
    {
        $gc = new \GearmanClient();
        $gc->addServer();
        $gc->setTimeout(1);

        $this->gc = $gc;
        print 'client created' . PHP_EOL;
    }

    public function ping($str)
    {
        return $this->gc->ping($str);
    }

    public function runJobs()
    {
        print 'runJobs called' . PHP_EOL;

        var_dump($this->gc->setCompleteCallback([$this, 'jobCallback']));
        var_dump($this->gc->setExceptionCallback([$this, 'exceptionCallback']));
        var_dump($this->gc->setFailCallback([$this, 'failCallback']));

        $jobStr = 'abcde';
        print('calling addTask()' . PHP_EOL);

        $gTask = $this->gc->addTask('myDefaultMethod', $jobStr, null, 'uniq1');

        if ($gTask instanceof \GearmanTask) {
            print 'OK' . PHP_EOL;
        }

        print 'runTasks call' . PHP_EOL;
        $this->gc->runTasks();
    }

    public function jobCallback($task)
    {
        print 'jobCallback called' . PHP_EOL;
        var_dump($task->data());

        return GEARMAN_SUCCESS;
    }

    public function exceptionCallback($task)
    {
        print 'exceptionCallback()' . PHP_EOL;
        var_dump($task->data());
        throw new \Exception($task->data());
    }

    public function failCallback($task)
    {
        print 'failCallback()' . PHP_EOL;
        var_dump($task->data());
    }
}



// ============= RUN =============

$bgc = new \Client();

$pingResult = $bgc->ping('xyz');
print 'ping called with result: ' . var_export($pingResult, 1) . PHP_EOL;

$bgc->runJobs();

To reproduce, just start the worker:

yes | xargs -n1 -I {} bash -c "php70 ./gearman_worker.php || echo 'WORKER FAILED'"

and run the client:

$ php70 ./gearman_client.php 
client created
ping called with result: true
runJobs called
bool(true)
bool(true)
bool(true)
calling addTask()
OK
runTasks call
failCallback()
string(5) "edcba"

It runs OK on PHP 5.5:

$ php ./gearman_client.php 
client created
ping called with result: true
runJobs called
bool(true)
bool(true)
bool(true)
calling addTask()
OK
runTasks call
jobCallback called
string(5) "edcba"

Could you please help me with this? Thank you

@wcgallego
Copy link
Owner

Thanks for the thorough bug report, @vojta! Will take a look

@wcgallego
Copy link
Owner

hey @vojta, I've made a change I think fixes the problem. Reopen if not.

I don't have many example of task work (and the unit tests for this are pretty poor, trying to fix that too!) so if this still isn't quite right or you see any others, please let me know. Thanks again for the help here!

@vojta
Copy link
Author

vojta commented Feb 2, 2016

Thank you! The testcase works, so you definitely fixed this one. But I'm still getting segfaults in real production code :( It's weird. I'll try to isolate this problem.

Will, please, how are your gearman calls that you are using in production? If we use the same as you do, we might run in less bugs like this :)

@wcgallego wcgallego reopened this Feb 2, 2016
@wcgallego
Copy link
Owner

Ok, I'll reopen. Sorry Dude :(

We're using Gearman jobs instead of tasks, so it's hitting different parts of the extension. Maybe it's trying to do several tasks in a row? Or the same task multiple times? I'll try to squeeze in some time to look at those, but if you could do the same (or try to narrow down) that'd be great!

@vojta
Copy link
Author

vojta commented Feb 4, 2016

I think this issue is resolved well, I just created another issue that touches different callback. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants