laravel-queue-rabbitmq icon indicating copy to clipboard operation
laravel-queue-rabbitmq copied to clipboard

Target [PhpAmqpLib\Connection\AbstractConnection] is not instantiable, BindingResolutionException.

Open yuiidev opened this issue 4 years ago • 2 comments

  • Laravel/Lumen version: 7.30.1
  • RabbitMQ version: 3.8.9
  • Package version: 10.2.2

Describe the bug

Bind exception thrown when trying to use a custom RabbitMQJob class.

Steps To Reproduce

  1. Extend RabbitMQJob
  2. Send message with the following payload
{
    "job": "App\\Jobs\\TestJob",
    "data": {
        "someMessage": "Hello, World!"
    },
    "id": "someid"
}

Current behavior

The following exception is thrown:

[2021-01-07 12:41:55] local.ERROR: Target [PhpAmqpLib\Connection\AbstractConnection] is not instantiable while building [App\Jobs\TestJob, VladimirYuldashev\LaravelQueueRabbitMQ\Queue\RabbitMQQueue]. {"exception":"[object] (Illuminate\\Contracts\\Container\\BindingResolutionException(code: 0): Target [PhpAmqpLib\\Connection\\AbstractConnection] is not instantiable while building [App\\Jobs\\TestJob, VladimirYuldashev\\LaravelQueueRabbitMQ\\Queue\\RabbitMQQueue]. at C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php:1017)
[stacktrace]
#0 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php(818): Illuminate\\Container\\Container->notInstantiable('PhpAmqpLib\\\\Conn...')
#1 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php(691): Illuminate\\Container\\Container->build('PhpAmqpLib\\\\Conn...')
#2 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Application.php(796): Illuminate\\Container\\Container->resolve('PhpAmqpLib\\\\Conn...', Array, true)
#3 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php(637): Illuminate\\Foundation\\Application->resolve('PhpAmqpLib\\\\Conn...', Array)
#4 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Application.php(781): Illuminate\\Container\\Container->make('PhpAmqpLib\\\\Conn...', Array)
#5 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php(959): Illuminate\\Foundation\\Application->make('PhpAmqpLib\\\\Conn...')
#6 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php(879): Illuminate\\Container\\Container->resolveClass(Object(ReflectionParameter))
#7 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php(840): Illuminate\\Container\\Container->resolveDependencies(Array)
#8 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php(691): Illuminate\\Container\\Container->build('VladimirYuldash...')
#9 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Application.php(796): Illuminate\\Container\\Container->resolve('VladimirYuldash...', Array, true)
#10 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php(637): Illuminate\\Foundation\\Application->resolve('VladimirYuldash...', Array)
#11 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Application.php(781): Illuminate\\Container\\Container->make('VladimirYuldash...', Array)
#12 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php(959): Illuminate\\Foundation\\Application->make('VladimirYuldash...')
#13 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php(879): Illuminate\\Container\\Container->resolveClass(Object(ReflectionParameter))
#14 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php(840): Illuminate\\Container\\Container->resolveDependencies(Array)
#15 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php(691): Illuminate\\Container\\Container->build('App\\\\Jobs\\\\TestJo...')
#16 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Application.php(796): Illuminate\\Container\\Container->resolve('App\\\\Jobs\\\\TestJo...', Array, true)
#17 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php(637): Illuminate\\Foundation\\Application->resolve('App\\\\Jobs\\\\TestJo...', Array)
#18 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Application.php(781): Illuminate\\Container\\Container->make('App\\\\Jobs\\\\TestJo...', Array)
#19 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\Jobs\\Job.php(225): Illuminate\\Foundation\\Application->make('App\\\\Jobs\\\\TestJo...')
#20 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\Jobs\\Job.php(212): Illuminate\\Queue\\Jobs\\Job->resolve('App\\\\Jobs\\\\TestJo...')
#21 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\Jobs\\Job.php(192): Illuminate\\Queue\\Jobs\\Job->failed(Object(Illuminate\\Contracts\\Container\\BindingResolutionException))
#22 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\Worker.php(498): Illuminate\\Queue\\Jobs\\Job->fail(Object(Illuminate\\Contracts\\Container\\BindingResolutionException))
#23 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\Worker.php(459): Illuminate\\Queue\\Worker->failJob(Object(VladimirYuldashev\\LaravelQueueRabbitMQ\\Queue\\Jobs\\RabbitMQJob), Object(Illuminate\\Contracts\\Container\\BindingResolutionException))
#24 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\Worker.php(383): Illuminate\\Queue\\Worker->markJobAsFailedIfWillExceedMaxAttempts('rabbitmq', Object(VladimirYuldashev\\LaravelQueueRabbitMQ\\Queue\\Jobs\\RabbitMQJob), 1, Object(Illuminate\\Contracts\\Container\\BindingResolutionException))
#25 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\Worker.php(360): Illuminate\\Queue\\Worker->handleJobException('rabbitmq', Object(VladimirYuldashev\\LaravelQueueRabbitMQ\\Queue\\Jobs\\RabbitMQJob), Object(Illuminate\\Queue\\WorkerOptions), Object(Illuminate\\Contracts\\Container\\BindingResolutionException))
#26 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\Worker.php(306): Illuminate\\Queue\\Worker->process('rabbitmq', Object(VladimirYuldashev\\LaravelQueueRabbitMQ\\Queue\\Jobs\\RabbitMQJob), Object(Illuminate\\Queue\\WorkerOptions))
#27 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\vladimir-yuldashev\\laravel-queue-rabbitmq\\src\\Consumer.php(99): Illuminate\\Queue\\Worker->runJob(Object(VladimirYuldashev\\LaravelQueueRabbitMQ\\Queue\\Jobs\\RabbitMQJob), 'rabbitmq', Object(Illuminate\\Queue\\WorkerOptions))
#28 [internal function]: VladimirYuldashev\\LaravelQueueRabbitMQ\\Consumer->VladimirYuldashev\\LaravelQueueRabbitMQ\\{closure}(Object(PhpAmqpLib\\Message\\AMQPMessage))
#29 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\php-amqplib\\php-amqplib\\PhpAmqpLib\\Channel\\AMQPChannel.php(1042): call_user_func(Object(Closure), Object(PhpAmqpLib\\Message\\AMQPMessage))
#30 [internal function]: PhpAmqpLib\\Channel\\AMQPChannel->basic_deliver(Object(PhpAmqpLib\\Wire\\AMQPReader), Object(PhpAmqpLib\\Message\\AMQPMessage))
#31 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\php-amqplib\\php-amqplib\\PhpAmqpLib\\Channel\\AbstractChannel.php(219): call_user_func(Array, Object(PhpAmqpLib\\Wire\\AMQPReader), Object(PhpAmqpLib\\Message\\AMQPMessage))
#32 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\php-amqplib\\php-amqplib\\PhpAmqpLib\\Channel\\AbstractChannel.php(373): PhpAmqpLib\\Channel\\AbstractChannel->dispatch('60,60', '\
laravel_18088\\x00...', Object(PhpAmqpLib\\Message\\AMQPMessage))
#33 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\vladimir-yuldashev\\laravel-queue-rabbitmq\\src\\Consumer.php(114): PhpAmqpLib\\Channel\\AbstractChannel->wait(NULL, true, NULL)
#34 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\Console\\WorkCommand.php(112): VladimirYuldashev\\LaravelQueueRabbitMQ\\Consumer->daemon('rabbitmq', 'test-queue', Object(Illuminate\\Queue\\WorkerOptions))
#35 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\Console\\WorkCommand.php(96): Illuminate\\Queue\\Console\\WorkCommand->runWorker('rabbitmq', 'test-queue')
#36 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\vladimir-yuldashev\\laravel-queue-rabbitmq\\src\\Console\\ConsumeCommand.php(40): Illuminate\\Queue\\Console\\WorkCommand->handle()
#37 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\BoundMethod.php(36): VladimirYuldashev\\LaravelQueueRabbitMQ\\Console\\ConsumeCommand->handle()
#38 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Util.php(37): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}()
#39 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\BoundMethod.php(93): Illuminate\\Container\\Util::unwrapIfClosure(Object(Closure))
#40 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\BoundMethod.php(37): Illuminate\\Container\\BoundMethod::callBoundMethod(Object(Illuminate\\Foundation\\Application), Array, Object(Closure))
#41 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Container\\Container.php(596): Illuminate\\Container\\BoundMethod::call(Object(Illuminate\\Foundation\\Application), Array, Array, NULL)
#42 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Console\\Command.php(134): Illuminate\\Container\\Container->call(Array)
#43 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\symfony\\console\\Command\\Command.php(255): Illuminate\\Console\\Command->execute(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Illuminate\\Console\\OutputStyle))
#44 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Console\\Command.php(121): Symfony\\Component\\Console\\Command\\Command->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Illuminate\\Console\\OutputStyle))
#45 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\symfony\\console\\Application.php(971): Illuminate\\Console\\Command->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#46 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\symfony\\console\\Application.php(290): Symfony\\Component\\Console\\Application->doRunCommand(Object(VladimirYuldashev\\LaravelQueueRabbitMQ\\Console\\ConsumeCommand), Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#47 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\symfony\\console\\Application.php(166): Symfony\\Component\\Console\\Application->doRun(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#48 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Console\\Application.php(93): Symfony\\Component\\Console\\Application->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#49 C:\\Users\\Demozo\\Code\\RabbitMQTest\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Console\\Kernel.php(129): Illuminate\\Console\\Application->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#50 C:\\Users\\Demozo\\Code\\RabbitMQTest\\artisan(37): Illuminate\\Foundation\\Console\\Kernel->handle(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#51 {main}
"} 

Expected behavior

Exception is not thrown and use of my class extending from RabbitMQJob is possible.

yuiidev avatar Jan 07 '21 14:01 yuiidev

This exception is also thrown on Laravel 8.32.1 running PHP 8.0.2.

In this Laravel 8 project I have aliased the php-amqplib/php-amqplib package from version 3.0.0-rc2 to version 2.12.3 as such:

{
    "require": {
        "php-amqplib/php-amqplib": "3.0.0-rc2 as 2.12.3",
        "vladimir-yuldashev/laravel-queue-rabbitmq": "^11.1"
    }
}

This lets me use laravel-queue-rabbitmq in conjuction with the php-amqplib version that supports PHP 8, but causes other issues to arise, like #413.

Weirdly enough this exception gets thrown after the job has already started executing business code, in other words the message has already been retrieved from the RabbitMQ queue meaning the connection has already been made. The only instances when the application interfaces with the AMQP protocol is during fetching of the message, and when marking the job as completed or failed, thus it does not make any sense for it to throw this particular exception in the middle of execution unless another exception has been thrown, which doesn't seem to be the case, judging from the logs:

[2021-03-10 13:18:06] local.INFO: Running job.  
[2021-03-10 13:18:06] local.DEBUG: Fetching JSON.  
[2021-03-10 13:18:06] local.DEBUG: Fetching XML. 
[2021-03-10 13:18:06] local.DEBUG: Hydrating JSON.  
[2021-03-10 13:18:06] local.ERROR: Target [PhpAmqpLib\Connection\AbstractConnection] is not instantiable while building [App\Queue\Jobs\RabbitMQJob, VladimirYuldashev\LaravelQueueRabbitMQ\Queue\RabbitMQQueue].

With commentary:

[2021-03-10 13:18:06] local.INFO: Running job.  -- Message has been retrieved from RabbitMQ queue
[2021-03-10 13:18:06] local.DEBUG: Fetching JSON.  -- If an exception is thrown here, it is logged first before being rethrown
[2021-03-10 13:18:06] local.DEBUG: Fetching XML.  -- If an exception is thrown here, it is logged first before being rethrown
[2021-03-10 13:18:06] local.DEBUG: Hydrating JSON.  -- If an exception is thrown here, it is logged first before being rethrown
[2021-03-10 13:18:06] local.ERROR: Target [PhpAmqpLib\Connection\AbstractConnection] is not instantiable while building [App\Queue\Jobs\RabbitMQJob, VladimirYuldashev\LaravelQueueRabbitMQ\Queue\RabbitMQQueue].

The fact that none of the steps taken during the execution of the job have logged an exception being thrown, make this very difficult for me to understand what exactly is happening and why Laravel is suddenly trying to instantiate an instance of AbstractConnection in the middle of code that does not in the slightest interface with the AMQP protocol.

yuiidev avatar Mar 10 '21 14:03 yuiidev

Ok so this is one of those issues where you are the only other person on the internet I've found to have this issue. Rather than post my theories on what the issue is, I'll just post how to replicate it, and how to fix it. I'll leave the solutions/explanations to someone more keen on digging through laravel/this packages source code.

This error only seems to pop up if your custom handler is throwing and exception AND you have not declared 'job' in the payload to laravel's liking. So I had something like this

public function fire()
{
    $payload = $this->payload();

    $class = \App\Actions\TestAction::class;
    $method = 'handle';

    ($this->instance = $this->resolve(\App\Actions\TestAction::class))->{$method}($this, $payload['data']);

    $this->delete();
}

public function getName()
{
    return static::class;
}


public function payload()
{
    return [
        'displayName' => $this->getName(),
        'job'  => $this->getName(),
        'data' => json_decode($this->getRawBody(), true),
    ];
}

So $payload['job'] is really just returning this classes name (it was complaining that it didn't exist, so I just put something in to make the error go away - rookie error)

My problem with this code, was that my TestAction class didn't actually have a method called 'handle' :roll_eyes: So an exception was being thrown. However, this is a job, so it doesn't just throw the exception straight away (i assume) it tries to make a 'failed job' then it will throw your exception. This is where the weird double instantiation thing is coming in I believe, it's just trying to create the failed job.

All you have to do to fix this problem, is set $payload['job'] the way laravel likes it ie SomeNamespace\ClassName@methodName. If you do this, you don't even need that custom fire class (unless you have some other reason to use it). So it should have looked something more like this:

public function payload()
{
    return [
        'displayName' => $this->getName(),
        'job'  => '\App\Actions\TestAction@handle',
        'data' => json_decode($this->getRawBody(), true),
    ];
}

Now everything works (after I actually created the handle method). I get the proper exceptions now so I can see what I broke, and why the job was failing, and the job seems to be failing successfully.

WillFoSho avatar May 30 '22 00:05 WillFoSho

Is this still an issue?

khepin avatar Feb 04 '23 00:02 khepin

I keep forgetting to come back to this. Likely implementing it in a new project soon, so I guess I'll find out. I can't remember the details fully because it's been a while. But it looks like my problem was not reading the docs properly. The readme clearly states to use \App\Actions\TestAction@handle as the job. So I think from my perspective it's fine to close.

WillFoSho avatar May 17 '23 23:05 WillFoSho