支持Enqueue
Enqueue 是一个 MIT 许可的开源项目,它的持续开发完全得益于社区和我们客户的支持。如果您想加入他们,请考虑:
异步事件
EnqueueBundle 允许您异步调度事件。 在幕后,它将您的监听器替换为向 MQ 发送消息的监听器。 该消息包含事件对象。 消费者一旦收到消息,就会恢复该事件并将其调度给异步监听器。
异步监听器的好处:
- 减少响应时间。工作被推迟到消费者进程。
- 更好的容错能力。异步监听器中的错误不会影响用户。消息将等到您修复错误为止。
- 更好的弹性。添加更多消费者以满足负载。
注意:在 Symfony 3.0 之前,事件会包含 eventDispatcher
,并且默认的 php 序列化转换器无法序列化对象。每个异步事件都应该注册一个转换器。阅读事件转换器。
配置
Symfony 事件当前是同步处理的,启用 EnqueueBundle 的异步配置会导致标记的监听器异步的延迟对消费者的操作。 如果您已经安装了该包,则启用 async_events
。
# app/config/config.yml
enqueue:
default:
async_events:
enabled: true
# 如果您想使用终端上发送消息,请使用spool_producer(它进一步缩短了响应时间):
# spool_producer: true
用例
为了使您的监听器异步,您必须向 kernel.event_listener
标签添加 async: true
属性,如下所示:
# app/config/config.yml
services:
acme.foo_listener:
class: 'AcmeBundle\Listener\FooListener'
tags:
- { name: 'kernel.event_listener', async: true, event: 'foo', method: 'onEvent' }
或注册到 kernel.event_subscriber
:
# app/config/config.yml
services:
test_async_subscriber:
class: 'AcmeBundle\Listener\TestAsyncSubscriber'
tags:
- { name: 'kernel.event_subscriber', async: true }
基本上就是这样。文档的其余部分将描述高级功能。
高级用例
您还可以直接添加异步监听器并为其注册自定义消息处理器:
# app/config/config.yml
services:
acme.async_foo_listener:
class: 'Enqueue\AsyncEventDispatcher\AsyncListener'
public: false
arguments: ['@enqueue.transport.default.context', '@enqueue.events.registry', 'a_queue_name']
tags:
- { name: 'kernel.event_listener', event: 'foo', method: 'onEvent' }
事件转换器
默认情况下,bundle 使用php 序列化转换器来通过 MQ 传递事件。 您可以通过实现 Enqueue\AsyncEventDispatcher\EventTransformer
接口来为每种事件类型编写转换器。 考虑下一个例子。它展示了如何发送包含 Doctrine 实体作为主题的事件:
<?php
namespace AcmeBundle\Listener;
// src/AcmeBundle/Listener/FooEventTransformer.php
use Enqueue\Client\Message;
use Enqueue\Consumption\Result;
use Interop\Queue\Message as QueueMessage;
use Enqueue\Util\JSON;
use Symfony\Component\EventDispatcher\Event;
use Enqueue\AsyncEventDispatcher\EventTransformer;
use Doctrine\Bundle\DoctrineBundle\Registry;
use Symfony\Component\EventDispatcher\GenericEvent;
class FooEventTransformer implements EventTransformer
{
/** @var Registry @doctrine */
private $doctrine;
public function __construct(Registry $doctrine)
{
$this->doctrine = $doctrine;
}
/**
* {@inheritdoc}
*
* @param GenericEvent $event
*/
public function toMessage($eventName, Event $event = null)
{
$entity = $event->getSubject();
$entityClass = get_class($entity);
$manager = $this->doctrine->getManagerForClass($entityClass);
$meta = $manager->getClassMetadata($entityClass);
$id = $meta->getIdentifierValues($entity);
$message = new Message();
$message->setBody([
'entityClass' => $entityClass,
'entityId' => $id,
'arguments' => $event->getArguments()
]);
return $message;
}
/**
* {@inheritdoc}
*/
public function toEvent($eventName, QueueMessage $message)
{
$data = JSON::decode($message->getBody());
$entityClass = $data['entityClass'];
$manager = $this->doctrine->getManagerForClass($entityClass);
if (false == $entity = $manager->find($entityClass, $data['entityId'])) {
return Result::reject('The entity could not be found.');
}
return new GenericEvent($entity, $data['arguments']);
}
}
并注册它:
# app/config/config.yml
services:
acme.foo_event_transformer:
class: 'AcmeBundle\Listener\FooEventTransformer'
arguments: ['@doctrine']
tags:
- {name: 'enqueue.event_transformer', eventName: 'foo' }
该 eventName
属性接受正则表达式。 你可以做使用eventName: '/foo\..*?/'
。 它将此转换器用于名称以 foo.
开头的所有事件。