Skip to content

Commit 4f5be8e

Browse files
authored
Merge pull request #929 from Lctrs/reset-services-extension
Add an extension to reset services
2 parents c098462 + 584054b commit 4f5be8e

File tree

8 files changed

+203
-4
lines changed

8 files changed

+203
-4
lines changed

docs/bundle/config_reference.md

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ enqueue:
6969
extensions:
7070
doctrine_ping_connection_extension: false
7171
doctrine_clear_identity_map_extension: false
72+
reset_services_extension: false
7273
signal_extension: true
7374
reply_extension: true
7475
```

docs/consumption/extensions.md

+6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ It clears Doctrine's identity map after a message is processed. It reduce memory
2222

2323
It test a database connection and if it is lost it does reconnect. Fixes "MySQL has gone away" errors.
2424

25+
## [ResetServicesExtension](https://github.com/php-enqueue/enqueue-dev/blob/master/pkg/enqueue-bundle/Consumption/Extension/ResetServicesExtension.php)
26+
27+
It resets all services with tag "kernel.reset".
28+
For example, this includes all monolog loggers if installed and will flush/clean all buffers,
29+
reset internal state, and get them back to a state in which they can receive log records again.
30+
2531
## [ReplyExtension](https://github.com/php-enqueue/enqueue-dev/blob/master/pkg/enqueue/Consumption/Extension/ReplyExtension.php)
2632

2733
It comes with RPC code and simplifies reply logic.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace Enqueue\Bundle\Consumption\Extension;
4+
5+
use Enqueue\Consumption\Context\MessageReceived;
6+
use Enqueue\Consumption\MessageReceivedExtensionInterface;
7+
use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter;
8+
9+
class ResetServicesExtension implements MessageReceivedExtensionInterface
10+
{
11+
/**
12+
* @var ServicesResetter
13+
*/
14+
private $resetter;
15+
16+
public function __construct(ServicesResetter $resetter)
17+
{
18+
$this->resetter = $resetter;
19+
}
20+
21+
public function onMessageReceived(MessageReceived $context): void
22+
{
23+
$context->getLogger()->debug('[ResetServicesExtension] Resetting services.');
24+
25+
$this->resetter->reset();
26+
}
27+
}

pkg/enqueue-bundle/DependencyInjection/Configuration.php

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public function getConfigTreeBuilder(): TreeBuilder
4747
->arrayNode('extensions')->addDefaultsIfNotSet()->children()
4848
->booleanNode('doctrine_ping_connection_extension')->defaultFalse()->end()
4949
->booleanNode('doctrine_clear_identity_map_extension')->defaultFalse()->end()
50+
->booleanNode('reset_services_extension')->defaultFalse()->end()
5051
->booleanNode('signal_extension')->defaultValue(function_exists('pcntl_signal_dispatch'))->end()
5152
->booleanNode('reply_extension')->defaultTrue()->end()
5253
->end()->end()

pkg/enqueue-bundle/DependencyInjection/EnqueueExtension.php

+28-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Enqueue\AsyncEventDispatcher\DependencyInjection\AsyncEventDispatcherExtension;
77
use Enqueue\Bundle\Consumption\Extension\DoctrineClearIdentityMapExtension;
88
use Enqueue\Bundle\Consumption\Extension\DoctrinePingConnectionExtension;
9+
use Enqueue\Bundle\Consumption\Extension\ResetServicesExtension;
910
use Enqueue\Bundle\Profiler\MessageQueueCollector;
1011
use Enqueue\Client\CommandSubscriberInterface;
1112
use Enqueue\Client\TopicSubscriberInterface;
@@ -136,6 +137,7 @@ public function load(array $configs, ContainerBuilder $container): void
136137
// extensions
137138
$this->loadDoctrinePingConnectionExtension($config, $container);
138139
$this->loadDoctrineClearIdentityMapExtension($config, $container);
140+
$this->loadResetServicesExtension($config, $container);
139141
$this->loadSignalExtension($config, $container);
140142
$this->loadReplyExtension($config, $container);
141143
}
@@ -210,7 +212,7 @@ private function loadDoctrinePingConnectionExtension(array $config, ContainerBui
210212
}
211213
}
212214

213-
if (false == $configNames) {
215+
if ([] === $configNames) {
214216
return;
215217
}
216218

@@ -233,7 +235,7 @@ private function loadDoctrineClearIdentityMapExtension(array $config, ContainerB
233235
}
234236
}
235237

236-
if (false == $configNames) {
238+
if ([] === $configNames) {
237239
return;
238240
}
239241

@@ -247,6 +249,28 @@ private function loadDoctrineClearIdentityMapExtension(array $config, ContainerB
247249
}
248250
}
249251

252+
private function loadResetServicesExtension(array $config, ContainerBuilder $container)
253+
{
254+
$configNames = [];
255+
foreach ($config as $name => $modules) {
256+
if ($modules['extensions']['reset_services_extension']) {
257+
$configNames[] = $name;
258+
}
259+
}
260+
261+
if ([] === $configNames) {
262+
return;
263+
}
264+
265+
$extension = $container->register('enqueue.consumption.reset_services_extension', ResetServicesExtension::class)
266+
->addArgument(new Reference('services_resetter'));
267+
268+
foreach ($configNames as $name) {
269+
$extension->addTag('enqueue.consumption_extension', ['client' => $name]);
270+
$extension->addTag('enqueue.transport.consumption_extension', ['transport' => $name]);
271+
}
272+
}
273+
250274
private function loadSignalExtension(array $config, ContainerBuilder $container): void
251275
{
252276
$configNames = [];
@@ -256,7 +280,7 @@ private function loadSignalExtension(array $config, ContainerBuilder $container)
256280
}
257281
}
258282

259-
if (false == $configNames) {
283+
if ([] === $configNames) {
260284
return;
261285
}
262286

@@ -277,7 +301,7 @@ private function loadReplyExtension(array $config, ContainerBuilder $container):
277301
}
278302
}
279303

280-
if (false == $configNames) {
304+
if ([] === $configNames) {
281305
return;
282306
}
283307

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
namespace Enqueue\Bundle\Tests\Unit\Consumption\Extension;
4+
5+
use Doctrine\Common\Persistence\ManagerRegistry;
6+
use Enqueue\Bundle\Consumption\Extension\ResetServicesExtension;
7+
use Enqueue\Consumption\Context\MessageReceived;
8+
use Interop\Queue\Consumer;
9+
use Interop\Queue\Context as InteropContext;
10+
use Interop\Queue\Message;
11+
use Interop\Queue\Processor;
12+
use PHPUnit\Framework\TestCase;
13+
use Psr\Log\LoggerInterface;
14+
use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter;
15+
16+
class ResetServicesExtensionTest extends TestCase
17+
{
18+
public function testCouldBeConstructedWithRequiredArguments()
19+
{
20+
new ResetServicesExtension($this->createResetterMock());
21+
}
22+
23+
public function testItShouldResetServices()
24+
{
25+
$resetter = $this->createResetterMock();
26+
$resetter
27+
->expects($this->once())
28+
->method('reset')
29+
;
30+
31+
$context = $this->createContext();
32+
$context->getLogger()
33+
->expects($this->once())
34+
->method('debug')
35+
->with('[ResetServicesExtension] Resetting services.')
36+
;
37+
38+
$extension = new ResetServicesExtension($resetter);
39+
$extension->onMessageReceived($context);
40+
}
41+
42+
protected function createContext(): MessageReceived
43+
{
44+
return new MessageReceived(
45+
$this->createMock(InteropContext::class),
46+
$this->createMock(Consumer::class),
47+
$this->createMock(Message::class),
48+
$this->createMock(Processor::class),
49+
1,
50+
$this->createMock(LoggerInterface::class)
51+
);
52+
}
53+
54+
/**
55+
* @return \PHPUnit_Framework_MockObject_MockObject|ManagerRegistry
56+
*/
57+
protected function createResetterMock(): ServicesResetter
58+
{
59+
return $this->createMock(ServicesResetter::class);
60+
}
61+
}

pkg/enqueue-bundle/Tests/Unit/DependencyInjection/ConfigurationTest.php

+43
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,49 @@ public function testDoctrineClearIdentityMapExtensionCouldBeEnabled()
336336
], $config);
337337
}
338338

339+
public function testResetServicesExtensionShouldBeDisabledByDefault()
340+
{
341+
$configuration = new Configuration(true);
342+
343+
$processor = new Processor();
344+
$config = $processor->processConfiguration($configuration, [[
345+
'default' => [
346+
'transport' => null,
347+
],
348+
]]);
349+
350+
$this->assertArraySubset([
351+
'default' => [
352+
'extensions' => [
353+
'reset_services_extension' => false,
354+
],
355+
],
356+
], $config);
357+
}
358+
359+
public function testResetServicesExtensionCouldBeEnabled()
360+
{
361+
$configuration = new Configuration(true);
362+
363+
$processor = new Processor();
364+
$config = $processor->processConfiguration($configuration, [[
365+
'default' => [
366+
'transport' => [],
367+
'extensions' => [
368+
'reset_services_extension' => true,
369+
],
370+
],
371+
]]);
372+
373+
$this->assertArraySubset([
374+
'default' => [
375+
'extensions' => [
376+
'reset_services_extension' => true,
377+
],
378+
],
379+
], $config);
380+
}
381+
339382
public function testSignalExtensionShouldBeEnabledIfPcntlExtensionIsLoaded()
340383
{
341384
$isLoaded = function_exists('pcntl_signal_dispatch');

pkg/enqueue-bundle/Tests/Unit/DependencyInjection/EnqueueExtensionTest.php

+36
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,42 @@ public function testShouldNotLoadDoctrineClearIdentityMapExtensionServiceIfDisab
384384
self::assertFalse($container->hasDefinition('enqueue.consumption.doctrine_clear_identity_map_extension'));
385385
}
386386

387+
public function testShouldLoadResetServicesExtensionServiceIfEnabled()
388+
{
389+
$container = $this->getContainerBuilder(true);
390+
391+
$extension = new EnqueueExtension();
392+
393+
$extension->load([[
394+
'default' => [
395+
'transport' => [],
396+
'extensions' => [
397+
'reset_services_extension' => true,
398+
],
399+
],
400+
]], $container);
401+
402+
self::assertTrue($container->hasDefinition('enqueue.consumption.reset_services_extension'));
403+
}
404+
405+
public function testShouldNotLoadResetServicesExtensionServiceIfDisabled()
406+
{
407+
$container = $this->getContainerBuilder(true);
408+
409+
$extension = new EnqueueExtension();
410+
411+
$extension->load([[
412+
'default' => [
413+
'transport' => [],
414+
'extensions' => [
415+
'reset_services_extension' => false,
416+
],
417+
],
418+
]], $container);
419+
420+
self::assertFalse($container->hasDefinition('enqueue.consumption.reset_services_extension'));
421+
}
422+
387423
public function testShouldLoadSignalExtensionServiceIfEnabled()
388424
{
389425
$container = $this->getContainerBuilder(true);

0 commit comments

Comments
 (0)