Symfony Messenger:使用消息接口作为处理程序时重试失败的消息__invoke type-hint

Posted

技术标签:

【中文标题】Symfony Messenger:使用消息接口作为处理程序时重试失败的消息__invoke type-hint【英文标题】:Symfony Messenger: Retrying failed messages when using a message interface as the handler __invoke type-hint 【发布时间】:2020-12-08 09:53:25 【问题描述】:

我在 Symfony 4.4 应用程序中使用 Symfony Messenger 组件。我正在通过 RabbitMQ 异步处理消息,并通过 Doctrine 传输将失败的消息存储在数据库中。

这是信使配置:

framework:
    messenger:
        failure_transport: failed

        buses:
            command_bus:
                middleware:
                    - doctrine_ping_connection

        transports:
            failed: 'doctrine://default?queue_name=failed'
            async_priority_high:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
                retry_strategy:
                    delay: 2000
                    max_retries: 5
                    multiplier: 2
                options:
                    exchange:
                        name: high
                    queues:
                        messages_high: ~

            async_priority_low:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
                retry_strategy:
                    delay: 3000
                    max_retries: 3
                    multiplier: 2
                options:
                    exchange:
                        name: low
                    queues:
                        messages_low: ~

        routing:
            'App\SampleMessageButHighPriority': async_priority_high
            'App\SampleMessageInterface': async_priority_low
            'App\OtherMessage': async_priority_low

这是一个示例处理程序,它处理实现SampleMessageInterface 接口的消息。

final class SampleMessageHandler implements MessageHandlerInterface

    private ProjectRepository $projectRepository;

    public function __construct(ProjectRepository $projectRepository)
    
        $this->projectRepository = $projectRepository;
    

    public function __invoke(SampleMessageInterface $message): void
    
        $project = $this->projectRepository->find($message->getProjectId()->toString());

        if ($project === null) 
            return;
        

        $this->someProcessor->__invoke($project);
    

在遇到任何消息失败之前一切正常。尝试重试或显示失败消息时,问题在失败后开始显示。让我们试试php bin/console messenger:failed:show 命令:

结果:

In PhpSerializer.php line 64:
                                                                               
  Cannot instantiate interface App\SampleMessageInterface                                                            

我猜Symfony需要反序列化失败的消息,之前序列化并存储在数据库中,但是因为它是一个接口,所以不能这样做。

我该如何解决这个问题?有没有办法使用类实现而不是接口来序列化失败的消息?

【问题讨论】:

请不要将代码放入图片中。使用```code``来发布你的格式化代码 对此我很抱歉,我刚刚更新了我的问题。谢谢你告诉我。 github.com/opengento/magento2-gdpr/issues/43 这里说这是一个缓存问题。也许您已经尝试清理缓存?你为什么用final这个关键词? Doc : symfony.com/doc/current/… 没有使用final关键字 可能的帮助下一个配置:``` messenger serializer: default_serializer: "messenger.transport.symfony_serializer" ``` 为我工作。在 4.2 中有它,但是在 4.4 之后(可能更早,没有检查),它默认更改为 phpSerializer。所以只需设置它,应该可以工作 【参考方案1】:

失败的消息被序列化地存储在数据库中。当您重试或显示这些消息时,它们会被反序列化。

只需将接口SampleMessageInterface 替换为类SampleMessage

【讨论】:

但是我怎样才能从只创建一个处理程序来处理所有SampleMessageInterface 消息中受益呢?或者这是不可能的,我应该开始为每个SampleMessageInterface 实现创建一个处理程序? 可以,但看起来 Messenger 的传输失败功能中存在错误。您能否检查一下包含失败消息的数据库并说出headers 列中的type 是什么?是SampleMessageInterface 还是别的什么? 它是SampleMessageInterface,所以我想这就是为什么它无法反序列化到发送的消息实施。我不知道这是一个错误还是预期的行为。 我认为这是一个错误。使用实际的类名而不是接口名进行序列化应该不是问题。 我刚刚报道了,让我们看看Symfony的人怎么说。谢谢!

以上是关于Symfony Messenger:使用消息接口作为处理程序时重试失败的消息__invoke type-hint的主要内容,如果未能解决你的问题,请参考以下文章

Symfony Messenger 如何确定应由哪个处理程序处理每种类型的消息?

在 Symfony Messenger 异步消息处理程序上使用选民/权限的最佳方式? [关闭]

使用 RMQ 在 Symfony Messenger 中处理来自不同命名空间的消息

Symfony Messenger 4.3 - 从理论传输中消费消息失败(抛出异常)

Symfony Messenger / RabbitMQ 检测请求消息

Symfony Messenger:重试延迟不适用于 Redis 传输