簡體   English   中英

使用RMQ處理來自Symfony Messenger中不同名稱空間的消息

[英]Handling messages from different namespaces in Symfony Messenger with RMQ

我正在使用微服務方法構建應用程序。 對於服務之間的通信,我將Symfony Messenger與RMQ傳輸一起使用。 基本上,一切正常,但是我所有的服務都必須在同一個命名空間中。 一旦我嘗試將它們分成自己的命名空間(如App\\MailApp\\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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM