使用RMQ中的Symfony Messenger中的不同名称空间处理消息



我正在使用Micro Services方法构建应用程序。对于服务之间的通信,我将Symfony Messenger与RMQ运输使用。基本上一切都很好,但是我所有的服务都必须在相同的名称空间中。一旦我试图将它们分成自己的名称空间,例如AppMailAppAuth,因此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名称空间的应用程序消费它。

我找不到任何有用的文档或互联网。我试图将AppEventUserRequestedPasswordResetAppMailEventUserRequestedPasswordReset相提并论,但没有运气。我猜这是对非正式化器的作用,但也找不到互联网上有用的东西。

通信本身在起作用,消息发送到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

请记住,这更像是概念证明,它可能会增强,但它正在起作用。

相关内容

最新更新