mikemadisonweb / yii2-rabbitmq

RabbitMQ Extension for Yii2
MIT License
72 stars 32 forks source link

Consumer opens many channels for one binding #40

Closed joorloohuis closed 5 years ago

joorloohuis commented 5 years ago

Hi Mikhail,

I noticed a situation where I have one consumer defined, with one callback for one queue with one wildcard binding ('#"), and I get one connection (as expected), but this connection has 4 channels. Only the 4th channel seems to be getting data. I observe this in the standard RabbitMQ admin webtool. An example yii2 config is attached below.

I've tried the same setup based on https://www.rabbitmq.com/tutorials/tutorial-five-php.html to try to identify the source of this behavior, but then I only get one channel, which is more or less what I expect.

Any comments or suggestions? It doesn't look like any messages are lost, but I haven't really put this to a stress test. It could become a factor in memory consumption for consumers, I think.

Test config (slightly edited to remove comments and application specific identifiers):

<?php

return [
    'class' => \mikemadisonweb\rabbitmq\Configuration::class,
    'auto_declare' => true,
    'connections' => [
        [
            'name' => 'default',
            'host' => '127.0.0.1',
            'port' => 5672,
            'user' => 'test',
            'password' => 'test',
            'vhost' => 'test',
        ],
    ],
    'exchanges' => [
        [
            'name' => 'test.in',
            'type' => 'topic',
            'passive' => false,
            'durable' => true,
            'auto_delete' => false,
        ],
    ],
    'queues' => [
        [
            'name' => 'incoming-bucket',
            'passive' => false,
            'durable' => true,
            'auto_delete' => false,
        ],
    ],
    'bindings' => [
        [
            'queue' => 'incoming-bucket',
            'exchange' => 'test.in',
            'routing_keys' => ['#'],
        ],
    ],
    'producers' => [
    ],
    'consumers' => [
        [
            'name' => 'incoming',
            'deserializer' => 'json_decode',
            'callbacks' => [
                'incoming-bucket' => \app\modules\amqp\components\IncomingConsumer::class,
            ],
        ],
    ],
    'logger' => [
        'log' => false,
        'category' => 'rabbitmq',
        'print_console' => true,
        'system_memory' => false,
    ],
];
joorloohuis commented 5 years ago

Followup: I noticed that the number of channels depends on the number of configured exchanges and queues. That lead me in the direction of autodeclare, and sure enough, when setting autodeclare to false I don't get the additional channels.

mikemadisonweb commented 5 years ago

Hello, Thank you for your investigation! Seems that you are right and the behavior that you mentioned are caused by the way that channel() method is written in the underlying library: https://github.com/php-amqplib/php-amqplib/blob/master/PhpAmqpLib/Connection/AbstractConnection.php#L644

So the fix should be trivial. We just need to reuse the channel using a variable and do not call the channel() method multiple times: https://github.com/mikemadisonweb/yii2-rabbitmq/blob/master/components/Routing.php#L91

I need to verify whether or not it cause some side effects, it could take a while. I will let you know when the fix will be ready.

joorloohuis commented 5 years ago

Great to get a quick response. Reusing the same channel seems like the way to go.

mikemadisonweb commented 5 years ago

Fixed in the new version: 2.1.0