問題的起因:
我們有一個訊息系統,處理各種非同步訊息。比如:管理人員給使用者的公告,使用者的動態釋出需要通知管理人員稽核,稽核透過後需要通知使用者和更新搜尋引擎的資料。這就存在著在某個地方會發兩個及以上的訊息。
訊息系統基於 nsq ,我們先來看看基本的程式碼, EventSender
類:
private $sender;
public static function getInstance()
{
if (!(self::$instance && (self::$instance instanceof self))) {
self::$instance = new self();
}
return self::$instance;
}
public function sendEvent($eventName, $topic, $data = [])
{
$this->init($topic);
return $this->sender->sendEvent($eventName, $data);
}
private function init($topic)
{
$this->sender = new Sender($this->senderName, $this->topicHost, $this->topicName, $this->appEnv);
}
上面只是抽取了部分程式碼。呼叫發訊息的方法看起來像這樣:
EventSender::getInstance()->sendEvent('UPDATE_INDEX', 'TOPIC_USER', ['user_id' => 1]);
EventSender::getInstance()->sendEvent('MESSAGE', 'TOPIC_MESSAGE', ['user_id' => 1]);
當使用者成功釋出動態以後,我們需要非同步的去更新使用者資訊,並給使用者傳送一個通知,告知他的資訊已被更新。因為更新操作和通知使用者是在兩個 TOPIC 上,所以上述程式碼只能收到更新訊息,通知使用者的資訊不能成功送達。
開始一直以為是不能同時驅動 nsq 的兩個 TOPIC ,在同步的情況下,TOPIC_USER 和 TOPIC_MESSAGE 只有一個能消化。在網上也沒找到相應的回答,無論怎麼除錯都收不到兩個訊息。
自以為對單例模式有一定的認識,之前沒遇到這樣的問題也沒注意。在仔細檢視程式碼後發現,每次傳送訊息都會去執行 init
方法,都會重新例項化 Sender
類,而每次例項化都會傳遞 TOPIC 引數。如果使用單例模式的話,當再呼叫發訊息方法的時候,因為例項已經存在,就不會再去初始化 TOPIC 。所以我們需要這樣來呼叫:
(new EventSender)->sendEvent('UPDATE_INDEX', 'TOPIC_USER', ['user_id' => 1]);
(new EventSender)->sendEvent('MESSAGE', 'TOPIC_MESSAGE', ['user_id' => 1]);
本作品採用《CC 協議》,轉載必須註明作者和本文連結