如何确保在关闭连接之前成功发布上一个AMQP消息?

时间:2016-09-09 08:51:42

标签: c++ rabbitmq amqp

我有多个进程作为一个系统一起工作。其中一个过程充当主要过程。当系统关闭时,每个进程都需要向主进程发送通知(通过RabbitMQ)然后退出。该程序是用C ++编写的,我正在使用AMQPCPP library

问题是有时通知未成功发布。我怀疑退出太快是问题的原因,因为AMQPCPP库在关闭连接之前没有机会发送消息。

AMQPCPP的文档说:

  

发布的消息通常不会被服务器确认,并且RabbitMQ不会发回报告以通知您消息是否已成功发布。因此,publish方法不会返回Deferred对象。

     

只要没有通过Channel :: onError()方法报告错误,您就可以安全地假设您的消息已经发送。

     

当您发布许多邮件时,这当然会成为一个问题。如果您在中途收到错误,则无法确定向代理发送了多少消息以及应该重新发布多少消息。如果这很重要,您可以将发布命令包装在事务中。在这种情况下,如果发生错误,RabbitMQ会自动回滚事务,并且实际上没有消息发布。

如果没有RabbitMQ服务器的确认,很难确定何时退出流程是安全的。此外,使用交易声音就像过度通知一样。

有人可以建议一个简单的解决方案,以便在不丢失最后通知的情况下正常关闭吗?

1 个答案:

答案 0 :(得分:0)

事实证明,我可以在关闭频道时设置回调。因此,当所有通道成功关闭时,我可以安全地关闭连接。我不完全确定此过程是否确保所有传出消息都已发布。但是从测试结果来看,问题似乎已经解决了。

class MyClass
{
    ...
    AMQP::TcpConnection m_tcpConnection;
    AMQP::TcpChannel m_channelA;
    AMQP::TcpChannel m_channelB;
    ...
};

void MyClass::stop(void)
{
    sendTerminateNotification();

    int remainChannel = 2;
    auto closeConnection = [&]() {
        --remainChannel;
        if (remainChannel == 0) {
            // close connection when all channels are closed.
            m_tcpConnection.close();
            ev::get_default_loop().break_loop();
        }
    };

    auto closeChannel = [&](AMQP::TcpChannel & channel) {
        channel.close()
            .onSuccess([&](void) { closeConnection(); })
            .onError([&](const char * msg)
                {
                    std::cout << "cannot close channel: "
                            << msg << std::endl;
                    // close the connection anyway
                    closeConnection();
                }
            );

    closeChannel(m_channelA);
    closeChannel(m_channelB);
}