![](/img/trans.png)
[英]How to avoid handling messages from “child” classes in Symfony Messenger?
[英]Handling messages from different namespaces in Symfony Messenger with RMQ
我正在使用微服務方法構建應用程序。 對於服務之間的通信,我將Symfony Messenger與RMQ傳輸一起使用。 基本上,一切正常,但是我所有的服務都必須在同一個命名空間中。 一旦我嘗試將它們分成自己的命名空間(如App\\Mail
, App\\Auth
等),messenger就抱怨缺少Event類,因為在發送給RMQ的消息頭中提供了整個名稱空間。 有什么辦法可以映射來自兩個不同名稱空間的事件?
例如, Auth
app調度事件UserRegistered
因此消息的類型為App\\Auth\\Event\\UserRegistered
。 我想在Mail應用程序中處理該事件,但Messenger無法使用它,因為我的事件和處理程序位於App\\Mail
命名空間下,因此它無法在“ Mail”應用程序中找到App\\Auth\\Event\\UserRegistered
類。
我得到的示例錯誤:
In Serializer.php line 85:
Could not decode message: Could not denormalize object of type App\Event\UserRequestedPasswordReset, no supporting normalizer found.
在這個確切的示例中,我從App
命名空間下的App
發送事件UserRequestedPasswordReset,並且嘗試在App\\Mail
命名空間下的App\\Mail
使用它。
在文檔或互聯網上找不到任何有用的信息。 我試圖在容器App\\Event\\UserRequestedPasswordReset
別名為App\\Mail\\Event\\UserRequestedPasswordReset
,但沒有運氣。 我猜想這對Denormalizers可行,但在互聯網上找不到任何有用的東西。
通信本身正在運行,消息被發送到RMQ並在其他服務中接收。 我為RMQ設置的是:我有多個隊列,每個服務一個。 我與綁定的那些隊列進行扇出交換。 每當產生事件時,我都會發布它以交換以將其填充到所有隊列中,以便感興趣的服務可以處理它們。
我的一項服務中的示例Messenger配置。 除了事件,我還使用Messenger來處理CQRS命令和查詢,因此我使用了三種不同的總線。
messenger:
default_bus: messenger.bus.commands
buses:
messenger.bus.commands:
middleware:
# - validation
# - doctrine_transaction
messenger.bus.queries:
middleware:
# - validation
messenger.bus.events:
default_middleware: allow_no_handlers
middleware:
# - validation
transports:
events:
dsn: "%env(MESSENGER_AMQP_DSN)%"
options:
exchange:
name: ecommerce_events
type: fanout
queue:
name: ecommerce_auth
routing:
'App\Event\UserCreated': events
'App\Event\UserModified': events
'App\Event\UserChangedPassword': events
'App\Event\UserRequestedPasswordReset': events
我想將我的應用程序保留在不同的名稱空間中,並且仍然能夠處理來自其他服務的事件
因此,在深入探討主題之后,我便能夠找到解決方案。
我只需要創建自定義序列化程序,然后在編碼過程中剝離名稱空間,然后在解碼過程中提供類型映射到實際事件類。 這是我的代碼
class EventsSerializer extends Serializer
{
/**
* {@inheritdoc}
*/
public function encode(Envelope $envelope): array
{
$data = parent::encode($envelope);
$data['headers']['type'] = $this->parseType($data['headers']['type']);
return $data;
}
public function decode(array $encodedEnvelope): Envelope
{
$translatedType = $this->translateType($encodedEnvelope['headers']['type']);
$encodedEnvelope['headers']['type'] = $translatedType;
return parent::decode($encodedEnvelope);
}
private function parseType(string $type)
{
return end(explode('\\', $type));
}
private function translateType($type)
{
$map = [
'UserCreated' => UserCreated::class,
'UserRequestedPasswordReset' => UserRequestedPasswordReset::class
];
if (array_key_exists($type, $map)) {
return $map[$type];
}
return $type;
}
}
然后在服務中
services:
_defaults:
autowire: false
autoconfigure: false
events_serializer:
class: App\Infrastructure\Messenger\RabbitMQ\Serializer\Events
autowire: true
並在Messenger配置中:
framework:
messenger:
default_bus: messenger.bus.commands
serializer:
default_serializer: events_serializer
symfony_serializer:
format: json
context: { }
buses:
messenger.bus.commands:
middleware:
# - validation
# - doctrine_transaction
messenger.bus.queries:
middleware:
# - validation
messenger.bus.events:
default_middleware: allow_no_handlers
middleware:
# - validation
transports:
events:
dsn: "%env(MESSENGER_AMQP_DSN)%"
serializer: events_serializer
options:
exchange:
name: ecommerce_events
type: fanout
queues:
ecommerce_mail: ~
請切記,這更像是概念證明,可能可以進行增強,但是它是有效的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.