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

register function only once to gearman worker #1141

Closed
wants to merge 0 commits into from

Conversation

cturbelin
Copy link
Contributor

Fix related to issue #1140 to only register the worker function only once to gearman


$this->worker->addFunction($this->destination->getName(), function (\GearmanJob $job) use (&$message) {
$message = GearmanMessage::jsonUnserialize($job->workload());
});
Copy link
Member

@makasim makasim Feb 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The message property looks suspicion to me. As well as public function receive_message which pollutes class interface.

What about this solution:

<?php

$message = null;

if (!$this->registered) {
    $this->worker->addFunction($this->destination->getName(), function (\GearmanJob $job) use (&$message) {
        $message = GearmanMessage::jsonUnserialize($job->workload());
    });
    $this->registered = true
}
            

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your comment and sorry for the delay !

I tried this solution, but it's not working (no message is handled after the first loop)
I suspect it's because the reference to $message is not valid anymore on the loops after the first one (the scope of this local variable on the next calls after passing it to the anonymous function is not clear to me).

The use of static variable is working, but need the second assignment (the fist one is only run when the static variable is created if I'm not wrong).

 static $message = null;
 $message = null;

It's working but I'm not confortable with this solution.
Other solution would be to use an extra class (possibly anonymous) to handle the message, it could be cleaner and safer than the use of a static variable, no ?

The block can become

            if (!$this->handler) {
                
                $this->handler = new class {
                    
                  protected $message;
                  
                  public function handle(\GearmanJob $job) {
                      $this->message = GearmanMessage::jsonUnserialize($job->workload());
                  }
                  
                  public function getMessage() {
                      return $this->message;
                  }
                  
                  public function reset() {
                      $this->message = null;
                  }
                };
                
                $this->worker->addFunction($this->destination->getName(), [$this->handler, 'handle' ]);
            } else {
                $this->handler->reset();
            }

It's working (and just a draft comments are missing), but a non anonymous class would be better, no (I dont know your policy about it) ?
I can rewrite and redo a PR with the solution you find the most acceptable !

Copy link
Member

@makasim makasim Apr 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's keep the current one, it simple and serve the same purpose

What about moving addFunction logic to the __consturct method? If that possible we can get rid of registered property. If not, that's fine as it is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but the current implementation register the function to gearman at each loop. To add it in the constructor we will need a reference to a persistent variable for message content (so it cannot be a local variable created in constructor) so either static or embedded into a class as it should be accessed by the receive() function later, or I am missing something (possible anyway).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am fine with message property. Looks like it is unavoidable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, if the worker callback is only registrer once we need either a property or a class to embed it
so we can just put this in constructor (using the message prop):

$this->worker->addFunction($this->destination->getName(), function (\GearmanJob $job) {
            $this->message = GearmanMessage::jsonUnserialize($job->workload());
});

and receive() becomes :

 //  [...]  timeout & handler
   $this->message = null;
    try {
        $this->worker->work();
    } finally {
        restore_error_handler();
    }
   return $this->message;
}

It's working on my side, I could make the PR if it's ok !

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeap, that looks great. Thank you for your effort.

@stale
Copy link

stale bot commented Mar 19, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

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

Successfully merging this pull request may close these issues.

2 participants