【问题标题】:Laravel + Rabbit = Crontab vs SupervisorLaravel + Rabbit = Crontab vs Supervisor
【发布时间】:2021-06-23 00:41:42
【问题描述】:

我有一个实现 rabbitmq 消费者 (bschmitt/laravel-amqp) 的 php 应用程序 (laravel 5.8)。
当应用程序启动时,为了控制消费者进程,也会启动一个主管进程。
我的主管配置文件:

[program:message-consume]
process_name=%(program_name)s_%(process_num)02d
command=php artisan message:consume 
directory=/var/www
autostart=true
autorestart=true
numprocs=1
redirect_stderr=true
stdout_logfile=/var/www/storage/logs/supervisor.log
stopwaitsecs=3600
startretries=20

消费命令

public function consume($routingKey)
{
  Log::info("[MessagingService][consume] start consuming key: " . $ROUTING_KEY . ".*");
  Amqp::consume($QUEUE_NAME, function ($message, $resolver) {
    # my code...
    $resolver->acknowledge($message);
  }, [
      'routing' => $ROUTING_KEY . '.*',
      'queue' => $QUEUE_NAME,
      'exchange' => $EXCHANGE,
      'exchange_type' => 'topic',
      'exchange_durable' => false,
      'queue_force_declare' => true,
      'queue_exclusive' => false,
      'persistent' => true, // set true if consume forever
  ]);
}

一切似乎都很好,但我意识到,如果有一段时间没有消息,应用程序就会停止接收消息!

进程仍在运行,主管没有做任何事情。
这是怎么回事?我从 rabbit 仪表板可以看到,没有消费者连接到该频道。

这个想法是创建一个 cron 脚本,每分钟调用一次 rabbitmq api 来检查队列中是否有消费者,以防万一,重新启动主管。

我正在使用 docker,所以我更改了我的 startup.sh 以添加 cron

#!/bin/bash

supervisord

crontab /etc/cron.d/check-consumer-cron
cron -f

php-fpm

但我开始问我问题。我过得好吗?我错过了什么吗?我需要主管吗?
如果我按以下方式更改startup.sh,会发生什么变化?

#!/bin/bash

php artisan message:consume 

crontab /etc/cron.d/check-consumer-cron
cron -f

php-fpm

【问题讨论】:

  • 我不知道您是自己实现了消费者端还是使用了包。但是如果有第三方包的话,我建议你按照RabbitMQ文档实现consumer端再试试。
  • 感谢@TohidDadashnezhad 的回答。您看到我在实施中遗漏了一些东西......可能是......我将在问题中添加信息。
  • 我不确定,但我认为将 `'exchange_durable' => false` 更改为 true 可能会解决此问题。

标签: laravel cron rabbitmq supervisord


【解决方案1】:

通过重新启动 Supervisor,您正在从错误的角度解决问题。主管的工作是让您的脚本运行,您需要了解为什么没有发生这种情况。

我相信你的问题实际上有两个部分:

  1. 如果闲置时间过长,您的消费者将断开连接。这可能是网络超时;在 AMQP 连接上配置“心跳”设置可能足以使其保持活动状态。
  2. Supervisor 未检测到此状态并重新启动您的使用者。那是因为它不监控消费者的网络状态,只监控 PHP 脚本是否仍在运行。您需要在您的消费者中使用一些代码来退出 PHP,而不是继续等待它永远不会收到的消息。

我不知道 Laravel 包装器,但通常消费者通过在某处看起来有点像这样的无限循环来工作:

while ( true ) {
   $connection->waitForAndProcessNextMessage();
}

每次有消息进来,或者超时到期,“waitForAndProcessNextMessage”方法(无论它实际调用什么)都会返回,此时你可以决定是继续循环,还是停止并退出脚本.您可以在那里进行状态检查,或者只查看脚本运行了多长时间:

while ( true ) {
   $connection->waitForAndProcessNextMessage();
   if ( ! $connection->isStillConnected() ) {
      break;
   }
   if ( minutesSinceConsumerStarted() > 30 ) {
      break;
   }
}

【讨论】:

    【解决方案2】:

    我想回答我的问题

    我过得好吗?我错过了什么吗?
    我使用的包是 php-amqplib 之上的一个包装器,这个包装器提供了有限的文档,而且非常糟糕的是,它无法控制内部结构。当然,我无法调试和检查发生了什么。 直接使用 php-amqplib 并遵循他们提供的示例,我再也没有遇到过这种行为。

    我需要主管吗?如果我按以下方式更改 startup.sh,会发生什么变化?
    这不是重点。

    【讨论】:

      猜你喜欢
      • 2015-10-22
      • 2022-12-28
      • 2017-06-28
      • 2012-03-08
      • 2020-12-07
      • 2019-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多