我正在使用Micro Services方法构建应用程序。对于服务之间的通信,我将Symfony Messenger与RMQ运输使用。基本上一切都很好,但是我所有的服务都必须在相同的名称空间中。一旦我试图将它们分成自己的名称空间,例如AppMail
,AppAuth
,因此Messenger在抱怨事件类别缺乏,因为在发送到RMQ的消息的标题中提供了整个Lamesapce。有什么方法可以从两个不同的名称空间映射事件?
实例Auth
应用程序派遣事件UserRegistered
因此消息具有AppAuthEventUserRegistered
的类型。我想在我的邮件应用程序中处理该事件,但是Messenger无法消耗它,因为我的活动和处理程序在AppMail
名称空间下,因此在"邮件"应用程序中找不到AppAuthEventUserRegistered
类。
示例错误我会得到:
In Serializer.php line 85:
Could not decode message: Could not denormalize object of type AppEventUserRequestedPasswordReset, no supporting normalizer found.
在这个确切的示例中,我正在从App
名称空间下的应用程序发送userRequestedPasswordreset,我正在尝试使用AppMail
名称空间的应用程序消费它。
我找不到任何有用的文档或互联网。我试图将AppEventUserRequestedPasswordReset
与AppMailEventUserRequestedPasswordReset
相提并论,但没有运气。我猜这是对非正式化器的作用,但也找不到互联网上有用的东西。
通信本身在起作用,消息发送到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:
'AppEventUserCreated': events
'AppEventUserModified': events
'AppEventUserChangedPassword': events
'AppEventUserRequestedPasswordReset': events
我想将我的应用程序保留在不同的命名空间中,并且仍然能够处理其他服务的事件
因此,在挖掘主题后,我就可以找到解决方案。
我只需要创建自定义序列化器,然后在编码期间,我将剥离名称空间,然后在解码过程中,我为实际事件类提供了映射。这是我的代码
class EventsSerializer extends Serializer
{
public function encode(Envelope $envelope): array
{
$data = parent::encode($envelope);
$data['headers']['type'] = $this->parseType($data['headers']['type']);
return $data;
}
private function parseType(string $type)
{
return end(explode('\', $type));
}
public function decode(array $encodedEnvelope): Envelope
{
$translatedType = $this->translateType($encodedEnvelope['headers']['type']);
$encodedEnvelope['headers']['type'] = $translatedType;
return parent::decode($encodedEnvelope);
}
private function translateType($type)
{
$map = [
'UserCreated' => UserCreated::class,
'UserRequestedPasswordReset' => UserRequestedPasswordReset::class
];
return $map[$type] ?? $type;
}
}
在Messenger配置中:
framework:
messenger:
serializer:
default_serializer: AppBundleSerializerEventsSerializer
请记住,这更像是概念证明,它可能会增强,但它正在起作用。