Php-amqplib: Keepalive and heartbeat on ssl

Created on 16 Feb 2016  路  8Comments  路  Source: php-amqplib/php-amqplib

So I got the following code:

<?php
//Consumer
if(is_file( __DIR__.'/config.php')){
        require_once __DIR__.'/config.php';
}else{
        require_once __DIR__.'/config.php.default';
}
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPSSLConnection;
use PhpAmqpLib\Message\AMQPMessage;

$callback = function($msg) {
        global $receiver_name;
        echo " [>] Received: '".$msg->body."'\n";
        exec($msg->body." 2>&1", $result);
        $reply = " [>] ".$receiver_name." replied :\n".implode("\n", $result)."\n";
        echo $reply;
        try{
                $msg->delivery_info['channel']->basic_publish(new AMQPMessage($reply),'',$msg->get('reply_to'));
        }catch(PhpAmqpLib\Exception\AMQPTimeoutException $e){
                print_r(" [x] AMQPTimeoutException ".$e->getMessage());
        }
};

while(true){
        try {
                $connection = new AMQPSSLConnection($host, $port, $user, $pass, "/", array('verify_peer' => false));
                $channel = $connection->channel();
                $channel->exchange_declare('to_all', 'fanout', false, false, false);
                $channel->exchange_declare($receiver_name, 'direct', false, false, false);
                $channel->queue_declare($receiver_name, false, false, true, false);
                $channel->queue_bind($receiver_name, 'to_all');
                $channel->queue_bind($receiver_name, $receiver_name);
                echo '[*] Waiting for messages at '.date("Y-m-d H:i:s").'. To exit press CTRL+C', "\n";
                $channel->basic_consume($receiver_name, '', false, true, false, false, $callback);
                while(count($channel->callbacks)) {
                        $channel->wait();
                }
                $channel->close();
                $connection->close();
        }catch(PhpAmqpLib\Exception\AMQPTimeoutException $e){
                print_r(" [x] AMQPTimeoutException ".$e->getMessage());
                sleep(5);
        }
}

I tried adding with no luck

$connection = new AMQPSSLConnection($host, $port, $user, $pass, "/", array('verify_peer' => false), array('keepalive' => true, 'heartbeat' => 30));

Which yells

PHP Warning:  socket_import_stream(): cannot represent a stream of type tcp_socket/ssl as a Socket Descriptor in /opt/serverstuff/vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/IO/StreamIO.php on line 427
PHP Warning:  socket_set_option() expects parameter 1 to be resource, boolean given in /opt/serverstuff/vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/IO/StreamIO.php on line 428

After which the connection yells and retries the connection.

 [x] AMQPTimeoutException Error sending data. Socket connection timed out

Even tried this in rabbitmq.config

  {tcp_listen_options, [
   {keepalive, true}
  ]}

What I'm doing to test is go to my router and do this

iptables -I FORWARD -s <consumer_ip> -j DROP
iptables -I FORWARD -d <consumer_ip> -j DROP

What I see is that the queue stays there in "idle" state even if I stop the consumer ( makes sense since the packets don't go through but I'd figure it should auto-drop after a while or something.

The context is that from time to time my server ip changes and the consumers don't seem to notice this .. they have an established connection through which nothing goes and I have to manually go and restart !

EDIT:
Also, having just this in the options array

array("heartbeat" => 5)

Throws this message and then reconnects to the server.

 RESOURCE_LOCKED - cannot obtain exclusive access to locked queue 'queue-name' in vhost '/'

And if I make the queue non-exclusive I get this:

ACCESS_REFUSED - queue 'bucharest-rds' in vhost '/' in exclusive use'

I'm doing something wrong and I don't get what.

All 8 comments

Hmm I'm wondering if it has something to do with this: https://bugs.php.net/bug.php?id=70939&edit=1

Would make sense .. still .. sad to see no updates for so many months ( or a workaround ).

@postalservice14 Would this work ?

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1);
socket_connect($socket, $host, $port);

I just noticed that the SSLConnection and Connection extend the AMQPStreamConnection .. altough there is some PhpAmqpLib/Wire/IO/StreamIO.php and a PhpAmqpLib/Wire/IO/SocketIO.php

Any updated on this? Looks like I have the exact same problem over here :(

We are encountering the same issue, we could PR but this is quite low level, so we'd rather someone more familiar with the codebase apply the fix (e.g. whether the suggestion at php.net works).

I will be releasing 2.9.0-rc1 this week. Please test this issue with it. If I don't get responses I will assume this issue is fixed. Thanks!

Hi all, to summarize, @d3xt3r01 touched 3 different things:
1st is that PHP does not support keepalive on SSL connections and we cannot do anything here, until #70939 is fixed, we can replace warnings with exceptions at most
2nd and also difficult to solve problem is a connection "aliveness", even keepalive does not help here, You must eable heartbeat and check it asap
3rd - RabbitMQ does not allow to redeclare existing queues. It means You cannot switch from exclusive to non-exclusive. RabbitMQ holds lock on that queue while consumer is connected. Maybe another process is still connected? Ayways, it would be better to use random names in Your case.

Thank you @ramunasd

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kozlice picture kozlice  路  4Comments

azngeek picture azngeek  路  7Comments

ltanme picture ltanme  路  8Comments

prolic picture prolic  路  6Comments

FrancisVarga picture FrancisVarga  路  5Comments