amphp/beanstalk

Call to a member function resolve on null

mmenozzi opened this issue · 4 comments

Hi,
I use the AMP's beanstalk client with https://github.com/webgriffe/esb.
Sometimes (but I never found the cause) the ESB application crashes with the following error:

PHP Fatal error:  Uncaught Error: Call to a member function resolve() on null in vendor/amphp/beanstalk/src/BeanstalkClient.php:38

That resolve is the one inside the response event callback of the client:

        $this->connection->addEventHandler("response", function ($response) {
            /** @var Deferred $deferred */
            $deferred = array_shift($this->deferreds);
            if ($response instanceof Throwable) {
                $deferred->fail($response);
            } else {
                $deferred->resolve($response);
            }
        });

And this is strange because only Deferred instances are added to the BeanstalkClient::$deferreds array.

array_unshift($this->deferreds, new Deferred);

$this->deferreds[] = $deferred = new Deferred;

So it seems that, sometimes, the response event is fired when the BeanstalkClient::$deferreds array is empty. Indeed, array_shift returns null if the array is empty (http://php.net/manual/en/function.array-shift.php).

I don't know how this could happen but happens...

Maybe we can prevent such error with a simple check:

        $this->connection->addEventHandler("response", function ($response) {
            if (empty($this->deferreds)) {
                return;
            }
            /** @var Deferred $deferred */
            $deferred = array_shift($this->deferreds);
            if ($response instanceof Throwable) {
                $deferred->fail($response);
            } else {
                $deferred->resolve($response);
            }
        });

But I don't know if the right thing to do.
@kelunik what do you think?

No, the check just hides the error. We have to find the cause.

My initial guess would be that it might happen on connection closes?

I don't think so. I did some other investigation and what can I say is that it happens during the execution of this method (but only sometimes, I think it depends on what is in the tube):

https://github.com/webgriffe/esb/blob/e2570d31533e47a95f5aa0e25693c7c2f06b80cc/src/Console/Controller/TubeController.php#L48

Do you see any unexpected usage in this method?

Closing after #26 is fixed, that's probably the cause.

Example

10\r\n
..........\r\n

If the following is in the buffer

10\r\n
..........

Then the if with the return is skipped: 4 + 2 + 14 < 10 + 4