如何使用Perl的AnyEvent :: RabbitMQ正确地与RabbitMQ断开连接?

时间:2016-01-14 09:13:50

标签: perl rabbitmq message-queue anyevent

我想以正确的方式与RabbitMQ断开连接。通过Perl的reviewing the source code AnyEvent::RabbitMQ(我正在使用),我发现close方法似乎关闭了所有向RabbitMQ打开的通道。

所以我

  1. 连接到RabbitMQ
  2. 开通了一个频道
  3. 宣布交换
  4. 绑定到该交换
  5. 宣布了一个队列
  6. 绑定到该队列
  7. close实例上执行AnyEvent::RabbitMQ方法(不是::Channel实例)
  8. 连接似乎已关闭,但RabbitMQ日志显示“AMQP连接”是“connection_closed_abruptly”。

    以下是该连接的完整RabbitMQ日志:

    =INFO REPORT==== 14-Jan-2016::10:02:15 ===
    accepting AMQP connection <0.10868.0> (127.0.0.1:57764 -> 127.0.0.1:5672)
    
    =WARNING REPORT==== 14-Jan-2016::10:02:16 ===
    closing AMQP connection <0.10868.0> (127.0.0.1:57764 -> 127.0.0.1:5672):
    connection_closed_abruptly
    

    以下是示例代码:

    #!/usr/bin/perl
    use strictures 1;
    
    use AnyEvent::RabbitMQ;
    use Data::Printer;
    
    my ( $rabbitmq, $rabbitmq_channel );
    
    my $condvar = AnyEvent->condvar;
    
    $rabbitmq = AnyEvent::RabbitMQ->new->load_xml_spec()->connect(
      host       => '127.0.0.1',
      port       => 5672,
      user       => 'guest',
      pass       => 'guest',
      vhost      => '/',
      timeout    => 1,
      tls        => 0,
      tune       => { heartbeat => 1 },
      on_success => sub {
        ($rabbitmq) = @_;
        $rabbitmq->open_channel(
          on_success => sub {
            ($rabbitmq_channel) = @_;
            $rabbitmq_channel->confirm;
            $rabbitmq_channel->declare_exchange(
              exchange   => 'test_exchange',
              type       => 'fanout',
              on_success => sub {
                $rabbitmq_channel->bind_exchange(
                  source      => 'test_exchange',
                  destination => 'test_exchange',
                  routing_key => '',
                  on_success  => sub {
                    $rabbitmq_channel->declare_queue(
                      queue      => 'test_queue',
                      on_success => sub {
                        $rabbitmq_channel->bind_queue(
                          queue       => 'test_queue',
                          exchange    => 'test_exchange',
                          routing_key => '',
                          on_success  => sub {
                            $rabbitmq->close;
                            undef $rabbitmq;
                          },
                          on_failure => sub { $condvar->send( __LINE__, @_ ) },
                        );
                      },
                      on_failure => sub { $condvar->send( __LINE__, @_ ) },
                    );
                  },
                  on_failure => sub { $condvar->send( __LINE__, @_ ) },
                );
              },
              on_failure => sub { $condvar->send( __LINE__, @_ ) },
            );
          },
          on_failure => sub { $condvar->send( __LINE__, @_ ) },
          on_return  => sub { $condvar->send( __LINE__, @_ ) },
          on_close   => sub { $condvar->send( __LINE__, @_ ) },
        );
      },
      on_failure      => sub { $condvar->send( __LINE__, @_ ) },
      on_read_failure => sub { $condvar->send( __LINE__, @_ ) },
      on_return       => sub { $condvar->send( __LINE__, @_ ) },
      on_close        => sub { $condvar->send( __LINE__, @_ ) },
    );
    
    my $reason = [ $condvar->recv ];
    p $reason;
    

    如何使用Perl的AnyEvent::RabbitMQ正确地与RabbitMQ断开连接?

2 个答案:

答案 0 :(得分:1)

有参考周期的指标。这些可以防止结构被正确破坏。

  1. &#34; my $rabbitmq; $rabbitmq = ...&#34;大喊参考周期的可能性。

  2. &#34; my $rabbitmq_channel; $rabbitmq_channel = ...&#34;大喊参考周期的可能性。

  3. $rabbitmq_channel归{存储于} $rabbitmq所有,但它也由$rabbitmq_channel的事件处理程序捕获。

  4. 标记为<===的更改会替换不可接受的代码。

    标记为<---的更改可能是必要的。如果回调中未定义$rabbitmq_channel,请删除此更改。

    use Scalar::Util qw( weaken );
    
    my $done_cv = AnyEvent->condvar;
    
    my $rabbitmq = AnyEvent::RabbitMQ->new->load_xml_spec()->connect(  # <===
      host       => '127.0.0.1',
      port       => 5672,
      user       => 'guest',
      pass       => 'guest',
      vhost      => '/',
      timeout    => 1,
      tls        => 0,
      tune       => { heartbeat => 1 },
      on_success => sub {
        my ($rabbitmq) = @_;  # <===
        $rabbitmq->open_channel(
          on_success => sub {
            my ($rabbitmq_channel) = @_;  # <===
            {  # <---
              my $rabbitmq_channel = weaken($rabbitmq_channel);  # <---
              $rabbitmq_channel->confirm;
              $rabbitmq_channel->declare_exchange(
                exchange   => 'test_exchange',
                type       => 'fanout',
                on_success => sub {
                  $rabbitmq_channel->bind_exchange(
                    source      => 'test_exchange',
                    destination => 'test_exchange',
                    routing_key => '',
                    on_success  => sub {
                      $rabbitmq_channel->declare_queue(
                        queue      => 'test_queue',
                        on_success => sub {
                          $rabbitmq_channel->bind_queue(
                            queue       => 'test_queue',
                            exchange    => 'test_exchange',
                            routing_key => '',
                            on_success  => sub { $done_cv->send( __LINE__, @_ ) },  # <===
                            on_failure => sub { $done_cv->send( __LINE__, @_ ) },
                          );
                        },
                        on_failure => sub { $done_cv->send( __LINE__, @_ ) },
                      );
                    },
                    on_failure => sub { $done_cv->send( __LINE__, @_ ) },
                  );
                },
                on_failure => sub { $done_cv->send( __LINE__, @_ ) },
              );
            }  # <---
          },
          on_failure => sub { $done_cv->send( __LINE__, @_ ) },
          on_return  => sub { $done_cv->send( __LINE__, @_ ) },
          on_close   => sub { $done_cv->send( __LINE__, @_ ) },
        );
      },
      on_failure      => sub { $done_cv->send( __LINE__, @_ ) },
      on_read_failure => sub { $done_cv->send( __LINE__, @_ ) },
      on_return       => sub { $done_cv->send( __LINE__, @_ ) },
      on_close        => sub { $done_cv->send( __LINE__, @_ ) },
    );
    
    my $reason = [ $done_cv->recv ];
    p $reason;
    

    我希望这会有所帮助。

答案 1 :(得分:0)

问题是AnyEvent :: RabbitMQ.pm库本身的一个错误。我不确定如何修复sub close本身,但关键部分是它永远不会执行在全局范围内将Connection::CloseConnection::CloseOk方法发送到RabbitMQ服务器的代码解构。设置AMQP连接后,可以通过执行以下操作进行确认。

$rabbitmq->_push_write(Net::AMQP::Protocol::Connection::Close->new());
$rabbitmq->_push_write(Net::AMQP::Protocol::Connection::CloseOk->new());

这有点像黑客,所以我正在以正确的方式去做,希望维护者能接受拉取请求。