【问题标题】:RabbitMQ not receiving messages when used with TopShelf as a Windows Service与 TopShelf 作为 Windows 服务一起使用时,RabbitMQ 不接收消息
【发布时间】:2017-08-14 17:11:12
【问题描述】:

我正在尝试将我的 RabbitMQ 微服务转换为 Windows 服务。我使用 TopShelf 进行转换。我的 RabbitMQ 微服务本身运行良好,但是当我将它作为服务运行时,它不再接收消息。在我的public static void Main(string[] args) 我有:

 HostFactory.Run(host =>
                {
                    host.Service<PersonService>(s =>                      
                    {
                        s.ConstructUsing(name => new PersonService());
                        s.WhenStarted(tc => tc.Start());             
                        s.WhenStopped(tc => tc.Stop());               
                    });
                    host.SetDescription("Windows service that provides database access totables."); 
                    host.SetDisplayName("Service");                   
                    host.SetServiceName("Service");
                });
            }

然后在我的PersonService 类中我有

public void Start() {
            ConsumeMessage();
        }

最后是我的ConsumeMessage 函数:

private static void ConsumeMessage() {
        MessagingConfig.SetInstance(new MessagingConstants());
        IMessageFactory pmfInst = MessageFactory.Instance;

        //message worker
        var factory = new ConnectionFactory() {
            HostName = MessagingConfig.Instance.GetBrokerHostName(),
            UserName = MessagingConfig.Instance.GetBrokerUserName(),
            Password = MessagingConfig.Instance.GetBrokerPassword()
        };

        var connection = factory.CreateConnection();

        using (var channel = connection.CreateModel()) {
            channel.QueueDeclare(queue: MessagingConfig.Instance.GetServiceQueueName(),
                                 durable: true,
                                 exclusive: false,
                                 autoDelete: false,
                                 arguments: null);

            channel.BasicQos(0, 1, false);

            var consumer = new EventingBasicConsumer(channel);

            channel.BasicConsume(queue: MessagingConfig.Instance.GetServiceQueueName(),
                                 noAck: false,
                                 consumer: consumer);

            Console.WriteLine("Service.");
            Console.WriteLine(" [x] Awaiting RPC requests");


            // Code Below Is Not Executed In Service
            consumer.Received += (model, ea) => {

                string response = null;

                var body = ea.Body;
                var props = ea.BasicProperties;
                var replyProps = channel.CreateBasicProperties();
                replyProps.CorrelationId = props.CorrelationId;

                string receivedMessage = null;

                try {
                    receivedMessage = Encoding.UTF8.GetString(body);
                    response = ProcessMessage(receivedMessage);
                }
                catch (Exception e) {
                    // Received message is not valid.
                    WinLogger.Log.Error(
                        "Errror Processing Message: " + receivedMessage + " :" + e.Message);

                    response = "";
                }
                finally {

                    var responseBytes = Encoding.UTF8.GetBytes(response);
                    channel.BasicPublish(exchange: "", routingKey: props.ReplyTo,
                    basicProperties: replyProps, body: responseBytes);
                    channel.BasicAck(deliveryTag: ea.DeliveryTag,
                    multiple: false);
                }
            };
            Console.ReadLine();
        }

查看A similar SO question,它似乎与 Windows 服务想要的返回有关,但我不确定如何调用 ConsumeMessage,因此执行了 consumer.Received += (model, ea) =&gt; {...};

编辑:看起来我的阻塞机制Console.ReadLine(); 被服务忽略了,所以它只是继续并处理消息消费者。那么如何阻止那里接收消息呢?

【问题讨论】:

    标签: c# .net windows-services rabbitmq


    【解决方案1】:

    您的代码使用using 构造,这意味着当您的OnStart 方法返回时,您的channel 实际上将被释放。 docs 建议在 OnStart 上进行初始化,因此在此处创建 channelconsumer,但不要使用 using

    this.connection = factory.CreateConnection();
    
    this.channel = connection.CreateModel();
    this.consumer = new EventingBasicConsumer(this.channel);
    

    那么在OnStart 方法完成后这些对象将继续存在。您应该在 OnStop 方法中处理它们。

    【讨论】:

    • 由于我使用的是 Topshelf,所以我有上面提到的tc =&gt; tc.Start();,我认为它与OnStart 相同?所以如果我理解正确的话,1. 建立连接、通道和消费者类成员,2. 在 Start() 中初始化,然后在 ConsumeMessage 中保持 consumer.Received += (model, ea) =&gt; {...} 的原样?是什么阻止 ConsumeMessage 完成并将 consumer.Received += (model, ea) =&gt; {...} 超出范围?
    • 是的,您的问题确实出在 using 语句中 - 在您的代码在 Console.ReadLine() 之前通过其大括号之后,您的频道将被处置,您将不会收到任何消息
    • 所以我让班级成员 private IConnection connection; private EventingBasicConsumer consumer; private IModel channel; 将初始化移动到 Start() 并删除了 using (var channel = connection.CreateModel()) { 当我作为命令行应用程序执行它时,我的结果返回但如果我将它作为服务运行,它不会返回 404 ,所以它在一定程度上解决了问题,让我明天再试一次,看看我是否可以解决它并接受你的回答
    • 要允许 Windows 服务访问数据库,我必须转到服务属性,登录,然后选择此帐户并输入我的凭据
    猜你喜欢
    • 2010-12-04
    • 1970-01-01
    • 1970-01-01
    • 2018-08-28
    • 2015-09-09
    • 1970-01-01
    • 2018-05-11
    • 1970-01-01
    相关资源
    最近更新 更多