使用 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;
}
}
将 MessageBusInterface 注入到处理图像上传的服务中。图像上传完成后,创建消息并分发它。
public function __construct(MessageBusInterface $messageBus)
{
$this->messageBus = $messageBus;
}
$message = new SetBackgroundColorToBlack($image->getIdentifier());
$this->messageBus->dispatch($message);
恭喜!你刚刚告诉了 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
最好将传输方式定义为环境变量。
###> symfony/messenger ###
MESSENGER_TRANSPORT_DSN=doctrine://default
###< symfony/messenger ###
完成工作
应该有人来做这件事。在项目的 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);
}
笔记:
- Symfony 非常智能,能够将消息与处理程序关联起来。只需在处理程序类中为 __invoke() 方法签名添加类型提示变量即可。
- 处理程序是一种服务,这意味着您可以注入其他服务。
- 也许图片无法获取,因为它已被他人删除。根据您的域名,图片可能必须存在,在这种情况下您需要抛出异常。
- 图像处理服务可能会抛出异常(很可能如此)。还记得我们定义了失败传输吗?默认情况下,所有消息都会重试 3 次,之后才会进入失败传输流程。
工作,工作,工作,工作,工作
定义一个将要处理这些消息的工作进程。php bin/console messenger:consume async
在生产车间安排一名主管人员,负责监督工人。
你觉得Symfony Messenger组件怎么样?你用什么来处理后台任务?你认为后台任务有必要吗?
文章来源:https://dev.to/bornfightcompany/background-jobs-with-symfony-messenger-component-p63