发布于 2026-01-06 2 阅读
0

使用 Symfony Messenger 组件的后台任务

使用 Symfony Messenger 组件的后台任务

假设你的客户提出这样的要求:每当上传一张图片时,就对它进行一些处理。比如更改背景颜色、转换成其他格式、添加水印……无论是什么,图像处理通常都是一个缓慢的过程,会显著增加“上传图片”操作所需的时间。 



稍后再做

但仔细想想,其实没必要在请求期间执行。用户根本不在乎这一点。他上传图片后,会继续做其他事,而图像处理会在后台进行。 


任何后台作业的流程大致如下:创建作业+将必要数据存储在某个位置以便稍后执行+执行作业



Symfony 消息组件(4.1 版本引入)可以帮你处理这个问题!



创建职位

想想执行任务所需的数据。在这种情况下,我们需要记住某种标识符,以便稍后获取图像。根据您的需求,它可以是数据库中存储的实体 ID、图像路径或其他内容。

在项目的 Message 文件夹中,创建一个类来封装该数据(并且不做其他任何事情)。

namespace App\Message;

class SetBackgroundColorToBlack
{
    /**
     * @var string
     */
    private $imageIdentifier;

    public function __construct(string $imageIdentifier)
    {
        $this->imageIdentifier = $imageIdentifier;
    }

    public function getImageIdentifier(): string
    {
        return $this->imageIdentifier;
    }
}
Enter fullscreen mode Exit fullscreen mode

将 MessageBusInterface 注入到处理图像上传的服务中。图像上传完成后,创建消息并分发它。

 public function __construct(MessageBusInterface $messageBus)
    {
        $this->messageBus = $messageBus;
    }

 $message = new SetBackgroundColorToBlack($image->getIdentifier());
 $this->messageBus->dispatch($message);
Enter fullscreen mode Exit fullscreen mode

恭喜!你刚刚告诉了 Symfony……嗯,其实也没什么特别的。

所有信息都发送到哪里?

你已经创建并发送了消息。接下来呢?把它存储在某个地方,以便能够处理它的类可以获取它。

在这种情况下,它被称为传输(transport)。Symfony 提供了多种传输选项和重试策略,因此请阅读文档并根据您的具体情况选择最合适的方案。我使用的是 Doctrine Transport,但它不适用于大型项目。

定义了两种传输方式:异步传输,用于处理 SetBackgroundColorToBlack 类型的消息;以及失败传输。

framework:
    messenger:
        failure_transport: failed
        transports:
            async:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
            failed:
                dsn: 'doctrine://default?queue_name=failed'

        routing:
            'App\Message\SetBackgroundColorToBlack': async
Enter fullscreen mode Exit fullscreen mode

最好将传输方式定义为环境变量。

###> symfony/messenger ###
MESSENGER_TRANSPORT_DSN=doctrine://default
###< symfony/messenger ###
Enter fullscreen mode Exit fullscreen mode

完成工作

应该有人来做这件事。在项目的 MessageHandler 目录中,创建 SetBackgroundColorToBlackHandler 类。

此类必须实现MessageHandlerInterface 接口

class SetBackgroundColorToBlackHandler implements MessageHandlerInterface
{
    /**
     * @var ImageProcessingService
     */
    private $imageProcessingService;

    /**
     * @var ImageRepository
     */
    private $imageRepository;

    public function __construct(ImageProcessingService $imageProcessingService, 
ImageRepository $imageRepository)
    {
        $this->imageProcessingService = $imageProcessingService;
        $this->imageRepository = $imageRepository;
    }

    public function __invoke(SetBackgroundColorToBlack $setBackgroundColorToBlack): void
    {
        $image = $this->imageRepository
                 ->get($setBackgroundColorToBlack->getImageIdentifier());

        if ($image === null) {
            return;
        }

        $this->imageProcessingService->setBackgroundColorToBlack($image);

    }
Enter fullscreen mode Exit fullscreen mode

笔记:

  • Symfony 非常智能,能够将消息与处理程序关联起来。只需在处理程序类中为 __invoke() 方法签名添加类型提示变量即可。
  • 处理程序是一种服务,这意味着您可以注入其他服务。
  • 也许图片无法获取,因为它已被他人删除。根据您的域名,图片可能必须存在,在这种情况下您需要抛出异常。
  • 图像处理服务可能会抛出异常(很可能如此)。还记得我们定义了失败传输吗?默认情况下,所有消息都会重试 3 次,之后才会进入失败传输流程。

工作,工作,工作,工作,工作

定义一个将要处理这些消息的工作进程。
php bin/console messenger:consume async

在生产车间安排一名主管人员,负责监督工人。

你觉得Symfony Messenger组件怎么样?你用什么来处理后台任务?你认为后台任务有必要吗?

文章来源:https://dev.to/bornfightcompany/background-jobs-with-symfony-messenger-component-p63