Skip to content

Commit b337fdd

Browse files
Allow usage of message handler classes as message handler names (#218)
* Allow usage of message handler classes as message handler names * Apply Rector changes (CI) * Update README.md --------- Co-authored-by: viktorprogger <viktorprogger@users.noreply.github.com>
1 parent 2bd3388 commit b337fdd

5 files changed

Lines changed: 94 additions & 4 deletions

File tree

README.md

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,16 @@ Each queue task consists of two parts:
5353
`Yiisoft\Queue\Message\Message`. For more complex cases you should implement the interface by your own.
5454
2. A message handler is a callable called by a `Yiisoft\Queue\Worker\Worker`. The handler handles each queue message.
5555

56-
For example, if you need to download and save a file, your message may look like the following:
56+
For example, if you need to download and save a file, your message creation may look like the following:
57+
- Message handler as the first parameter
58+
- Message data as the second parameter
5759

5860
```php
5961
$data = [
6062
'url' => $url,
6163
'destinationFile' => $filename,
6264
];
63-
$message = new \Yiisoft\Queue\Message\Message('file-download', $data);
65+
$message = new \Yiisoft\Queue\Message\Message(FileDownloader::class, $data);
6466
```
6567

6668
Then you should push it to the queue:
@@ -93,9 +95,8 @@ class FileDownloader
9395
The last thing we should do is to create a configuration for the `Yiisoft\Queue\Worker\Worker`:
9496

9597
```php
96-
$handlers = ['file-download' => [new FileDownloader('/path/to/save/files'), 'handle']];
9798
$worker = new \Yiisoft\Queue\Worker\Worker(
98-
$handlers, // Here it is
99+
[],
99100
$logger,
100101
$injector,
101102
$container
@@ -134,6 +135,28 @@ $status->isReserved();
134135
$status->isDone();
135136
```
136137

138+
## Custom handler names
139+
### Custom handler names
140+
141+
By default, when you push a message to the queue, the message handler name is the fully qualified class name of the handler.
142+
This can be useful for most cases, but sometimes you may want to use a shorter name or arbitrary string as the handler name.
143+
This can be useful when you want to reduce the amount of data being passed or when you communicate with external systems.
144+
145+
To use a custom handler name before message push, you can pass it as the first argument `Message` when creating it:
146+
```php
147+
new Message('handler-name', $data);
148+
```
149+
150+
To use a custom handler name on message consume, you should configure handler mapping for the `Worker` class:
151+
```php
152+
$worker = new \Yiisoft\Queue\Worker\Worker(
153+
['handler-name' => FooHandler::class],
154+
$logger,
155+
$injector,
156+
$container
157+
);
158+
```
159+
137160
## Different queue channels
138161

139162
Often we need to push to different queue channels with an only application. There is the `QueueFactory` class to make
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yiisoft\Queue\Message;
6+
7+
interface MessageHandlerInterface
8+
{
9+
public function handle(MessageInterface $message): void;
10+
}

src/Worker/Worker.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Throwable;
1616
use Yiisoft\Injector\Injector;
1717
use Yiisoft\Queue\Exception\JobFailureException;
18+
use Yiisoft\Queue\Message\MessageHandlerInterface;
1819
use Yiisoft\Queue\Message\MessageInterface;
1920
use Yiisoft\Queue\Middleware\Consume\ConsumeFinalHandler;
2021
use Yiisoft\Queue\Middleware\Consume\ConsumeMiddlewareDispatcher;
@@ -77,6 +78,18 @@ public function process(MessageInterface $message, QueueInterface $queue): Messa
7778
private function getHandler(string $name): ?callable
7879
{
7980
if (!array_key_exists($name, $this->handlersCached)) {
81+
$definition = $this->handlers[$name] ?? null;
82+
if ($definition === null && $this->container->has($name)) {
83+
$handler = $this->container->get($name);
84+
if ($handler instanceof MessageHandlerInterface) {
85+
$this->handlersCached[$name] = $handler->handle(...);
86+
87+
return $this->handlersCached[$name];
88+
}
89+
90+
return null;
91+
}
92+
8093
$this->handlersCached[$name] = $this->prepare($this->handlers[$name] ?? null);
8194
}
8295

tests/Integration/MessageConsumingTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Yiisoft\Queue\Middleware\Consume\MiddlewareFactoryConsumeInterface;
1414
use Yiisoft\Queue\Middleware\FailureHandling\FailureMiddlewareDispatcher;
1515
use Yiisoft\Queue\Middleware\FailureHandling\MiddlewareFactoryFailureInterface;
16+
use Yiisoft\Queue\Tests\Integration\Support\TestHandler;
1617
use Yiisoft\Queue\Tests\TestCase;
1718
use Yiisoft\Queue\Worker\Worker;
1819

@@ -41,4 +42,27 @@ public function testMessagesConsumed(): void
4142

4243
$this->assertEquals($messages, $this->messagesProcessed);
4344
}
45+
46+
public function testMessagesConsumedByHandlerClass(): void
47+
{
48+
$handler = new TestHandler();
49+
$container = $this->createMock(ContainerInterface::class);
50+
$container->method('get')->with(TestHandler::class)->willReturn($handler);
51+
$container->method('has')->with(TestHandler::class)->willReturn(true);
52+
$worker = new Worker(
53+
[],
54+
new NullLogger(),
55+
new Injector($container),
56+
$container,
57+
new ConsumeMiddlewareDispatcher($this->createMock(MiddlewareFactoryConsumeInterface::class)),
58+
new FailureMiddlewareDispatcher($this->createMock(MiddlewareFactoryFailureInterface::class), [])
59+
);
60+
61+
$messages = [1, 'foo', 'bar-baz'];
62+
foreach ($messages as $message) {
63+
$worker->process(new Message(TestHandler::class, $message), $this->getQueue());
64+
}
65+
66+
$this->assertEquals($messages, $handler->messagesProcessed);
67+
}
4468
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yiisoft\Queue\Tests\Integration\Support;
6+
7+
use Yiisoft\Queue\Message\MessageHandlerInterface;
8+
use Yiisoft\Queue\Message\MessageInterface;
9+
10+
final class TestHandler implements MessageHandlerInterface
11+
{
12+
public function __construct(public array $messagesProcessed = [])
13+
{
14+
}
15+
16+
public function handle(MessageInterface $message): void
17+
{
18+
$this->messagesProcessed[] = $message->getData();
19+
}
20+
}

0 commit comments

Comments
 (0)