2017-12-27 27 views
0

내 프로젝트에 Server Side Events 역학을 사용하려고했습니다. (이것은 스테로이드에 대한 긴 폴링과 같습니다)RabbitMQ와의 연결 해제 후 Apache 프로세스가 종료되지 않습니다.

"Sending events from the server"의 예제는 아름답게 작동합니다. 몇 초 후에 연결 해제에서 아파치 프로세스가 종료됩니다. 이 방법은 잘 작동합니다.

BUT! RabbitMQ을 사용하려고하면 서버가 브라우저와 연결을 끊은 후에 프로세스가 종료되지 않습니다 (es.close()). 그리고 프로세스는 그대로두고 도커 컨테이너가 다시 시작된 후에 만 ​​죽습니다.

connection_abortedconnection_status이 전혀 작동하지 않습니다. connection_aborted은 연결이 끊긴 후에도 0 만 반환하고 connection_status는 CONNECTION_NORMAL을 반환합니다. RabbitMQ를 사용할 때만 발생합니다. RMQ가 없으면이 기능이 잘 작동합니다.

ignore_user_abort(false)도 작동하지 않습니다.

코드 예제 :

  • 브라우저가 서버에 SSE 연결을 설정합니다 : 어떻게됩니까

    <?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(); 
        } 
    } 
    

    . var es = new EventSource(url);

  • Apache2는이 요청을 처리하기위한 새로운 프로세스를 생성합니다.
  • PHP는 새로운 대기열을 생성하고 그것에 연결합니다.
  • 브라우저가 닫히는 연결 es.close()
  • 아파치 2는 프로세스를 죽이지 않으며 그대로 유지됩니다. RabbitMQ의 대기열은 삭제되지 않습니다. 몇 가지 재 연결을하면 여러 개의 프로세스와 여러 개의 대기열이 생성됩니다 (1 재 연결 = 1 프로세스 = 1 대기열).
  • 나는 모든 탭을 닫습니다 - 프로세스가 살아 있습니다. 나는 브라우저를 닫는다 - 같은 상황.

일종의 PHP 버그가 있습니다. 아니면 Apach2?

내가 사용하는 :

  • 마지막 도커 및

일부 스크린 샷 (이 두가지 버전의 PHP에서 발생)

  • php:7.1.12-apache or php:5.6-apache 이미지를 고정 표시기 - 구성 :

    RabbitMQ queues

    Processes

    제발, 무슨 일이 일어나는지 알아 내도록 도와주세요.

    P. 미안해, 내 영어로. 실수 나 오타를 찾을 수 있다면 주석에서 가리 키십시오. 나는 매우 감사 할 것입니다.

  • 답변

    0

    send() 또는 subscribe() (또는 둘 다)을 서버 측 이벤트 중에 사용하고 있다고 말할 수는 없습니다. subscribe()을 사용한다고 가정하면 버그가 없습니다.이 루프 : 프로세스가 살해되거나 연결이 원격 RabbitMQ에서 닫힐 때까지

    while (count($channel->callbacks)) { 
        if (connection_aborted()) { 
         break; 
        } 
    
        try { 
         $channel->wait(null, true, 5); 
        } catch (AMQPTimeoutException $exception) { 
        } 
    } 
    

    가 실행됩니다. 대기중인 메시지를 청취 할 때 정상입니다. 어떤 시점에서 루프를 중지해야하는 경우 변수를 설정하여 루프를 체크인하거나 SSE가 종료 될 때 예외를 throw 할 수 있습니다.

    +0

    아니요. 프로세스는 apache2에 의해 종료되지 않습니다. 이것은 2004 년 이래 가장 오래된 버그입니다 - https://bugs.php.net/bug.php?id=30301. 'connection_aborted'와'connection_status' 함수가 작동하지 않습니다. 그리고 이것들을 고칠 방법이 없습니다. Websocketd (끝 부분에 D가 있음)를 사용하는 것이 좋습니다 –