2017-12-27 568 views
0

我試圖在我的項目中使用Server Side Events機制。 (這類似於類固醇上的長輪詢)Apache進程不會在與RabbitMQ斷開連接後死亡

來自「Sending events from the server」字幕的例子效果非常好。幾秒鐘後,斷開連接,apache進程終止。此方法工作正常。

但是!如果我嘗試使用RabbitMQ,則在瀏覽器從服務器斷開連接後,Apache不會導致進程中斷(es.close())。並且進程保持原樣並在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

請幫我弄清楚是怎麼回事...

附:對不起我的英語不好。如果您可以找到錯誤或錯字,請在評論中指出它。我會很感激:)

回答

0

,如果你在你的服務器端事件使用send()subscribe()(或兩者)你不說。假設你正在使用subscribe()沒有錯誤。這個循環:

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

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

將運行,直到進程被殺死或連接遠離的RabbitMQ關閉。收聽排隊消息時這是正常的。如果你需要在某個時候停止循環,你可以設置一個變量來檢查循環,或者在SSE結束時拋出異常(儘管我覺得這很尷尬)。

+0

編號進程不會被apache2殺死。這是自2004年以來最古老的錯誤 - https://bugs.php.net/bug.php?id=30301。 'connection_aborted'和'connection_status'函數不起作用。而這些無法解決它。對我來說,最好使用Websocketd(最後用D) –