与RabbitMQ断开连接后,Apache进程不会死亡

时间:2017-12-27 17:28:46

标签: php apache docker rabbitmq amqp

我试图在我的项目中使用Server Side Events机制。 (这就像对类固醇的长轮询)

Sending events from the server”字幕的示例效果很好。几秒钟后,断开连接,apache进程被终止。这种方法很好。

BUT!如果我尝试使用RabbitMQ,则在浏览器与服务器(es.close())断开连接后,Apache不会终止该进程。并且进程按原样离开,并且仅在docker容器重新启动后才被杀死。

connection_abortedconnection_status根本不起作用。 connection_aborted仅返回0,即使断开连接,connection_status也会返回CONNECTION_NORMAL。它只在我使用RabbitMQ时才会发生。没有RMQ,这个功能运作良好。

ignore_user_abort(false)也不起作用。

代码示例:

<?php
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Connection\AbstractConnection;
use PhpAmqpLib\Exception\AMQPTimeoutException;
use PhpAmqpLib\Message\AMQPMessage;

class RequestsRabbit
{
    protected $rabbit;

    /** @var AMQPChannel */
    protected $channel;

    public $exchange = 'requests.events';

    public function __construct(AbstractConnection $rabbit)
    {
        $this->rabbit = $rabbit;
    }

    public function getChannel()
    {
        if ($this->channel === null) {
            $channel = $this->rabbit->channel();

            $channel->exchange_declare($this->exchange, 'fanout', false, false, false);

            $this->channel = $channel;
        }

        return $this->channel;
    }

    public function send($message)
    {
        $channel = $this->getChannel();

        $message = json_encode($message);

        $channel->basic_publish(new AMQPMessage($message), $this->exchange);
    }

    public function subscribe(callable $callable)
    {
        $channel = $this->getChannel();

        list($queue_name) = $channel->queue_declare('', false, false, true, false);

        $channel->queue_bind($queue_name, $this->exchange);

        $callback = function (AMQPMessage $msg) use ($callable) {
            call_user_func($callable, json_decode($msg->body));
        };

        $channel->basic_consume($queue_name, '', false, true, false, false, $callback);

        while (count($channel->callbacks)) {
            if (connection_aborted()) {
                break;
            }

            try {
                $channel->wait(null, true, 5);
            } catch (AMQPTimeoutException $exception) {
            }
        }

        $channel->close();
        $this->rabbit->close();
    }
}

会发生什么:

  • 浏览器建立与服务器的SSE连接。 var es = new EventSource(url);
  • Apache2生成新进程来处理此请求。
  • PHP生成一个新的队列并连接到它。
  • 浏览器关闭连接es.close()
  • Apache2不会杀死进程并保持原样。 RabbitMQ的队列不会被删除。如果我进行一些重新连接,它会产生一堆进程和一堆队列(1个重新连接= 1个进程= 1个队列)。
  • 我关闭所有标签 - 进程处于活动状态。我关闭浏览器 - 同样的情况。

看起来某种PHP错误。还是Apach2?

我用的是什么:

一些截图:

RabbitMQ queues

Processes

请帮我弄清楚发生了什么......

P.S。对不起我的英语不好。如果您可以找到错误或拼写错误,请在评论中指出。我将非常感激:)

1 个答案:

答案 0 :(得分:0)

您没有说在服务器端事件期间是否使用send()subscribe()(或两者)。假设您正在使用subscribe(),则没有错误。这个循环:

while (count($channel->callbacks)) {
    if (connection_aborted()) {
        break;
    }

    try {
        $channel->wait(null, true, 5);
    } catch (AMQPTimeoutException $exception) {
    }
}

将一直运行,直到进程被终止或从RabbitMQ远程关闭连接。这在侦听排队的消息时是正常的。如果你需要在某个时刻停止循环,你可以设置一个变量来检查循环,或者在SSE结束时抛出一个异常(虽然我觉得这很尴尬)。