Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Messenger] Add a scheduler component #47112

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
"symfony/rate-limiter": "self.version",
"symfony/remote-event": "self.version",
"symfony/routing": "self.version",
"symfony/scheduler": "self.version",
"symfony/security-bundle": "self.version",
"symfony/security-core": "self.version",
"symfony/security-csrf": "self.version",
Expand Down Expand Up @@ -131,6 +132,7 @@
"doctrine/data-fixtures": "^1.1",
"doctrine/dbal": "^2.13.1|^3.0",
"doctrine/orm": "^2.12",
"dragonmantank/cron-expression": "^3",
"egulias/email-validator": "^2.1.10|^3.1|^4",
"guzzlehttp/promises": "^1.4",
"league/html-to-markdown": "^5.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class UnusedTagsPass implements CompilerPassInterface
'routing.expression_language_provider',
'routing.loader',
'routing.route_loader',
'scheduler.schedule_provider',
'security.authenticator.login_linker',
'security.expression_language_provider',
'security.remember_me_aware',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
use Symfony\Component\RateLimiter\Policy\TokenBucketLimiter;
use Symfony\Component\RemoteEvent\RemoteEvent;
use Symfony\Component\Scheduler\Messenger\SchedulerTransportFactory;
use Symfony\Component\Semaphore\Semaphore;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Translation\Translator;
Expand Down Expand Up @@ -173,6 +174,7 @@ public function getConfigTreeBuilder(): TreeBuilder
$this->addLockSection($rootNode, $enableIfStandalone);
$this->addSemaphoreSection($rootNode, $enableIfStandalone);
$this->addMessengerSection($rootNode, $enableIfStandalone);
$this->addSchedulerSection($rootNode, $enableIfStandalone);
$this->addRobotsIndexSection($rootNode);
$this->addHttpClientSection($rootNode, $enableIfStandalone);
$this->addMailerSection($rootNode, $enableIfStandalone);
Expand Down Expand Up @@ -1606,6 +1608,18 @@ function ($a) {
;
}

private function addSchedulerSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone): void
{
$rootNode
->children()
->arrayNode('scheduler')
->info('Scheduler configuration')
->{$enableIfStandalone('symfony/scheduler', SchedulerTransportFactory::class)}()
->end()
->end()
;
}

private function addRobotsIndexSection(ArrayNodeDefinition $rootNode): void
{
$rootNode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@
use Symfony\Component\RemoteEvent\Attribute\AsRemoteEventConsumer;
use Symfony\Component\RemoteEvent\RemoteEvent;
use Symfony\Component\Routing\Loader\Psr4DirectoryLoader;
use Symfony\Component\Scheduler\Attribute\AsSchedule;
use Symfony\Component\Scheduler\Messenger\SchedulerTransportFactory;
use Symfony\Component\Security\Core\AuthenticationEvents;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
Expand Down Expand Up @@ -526,9 +528,18 @@ public function load(array $configs, ContainerBuilder $container)
// validation depends on form, annotations being registered
$this->registerValidationConfiguration($config['validation'], $container, $loader, $propertyInfoEnabled);

$messengerEnabled = $this->readConfigEnabled('messenger', $container, $config['messenger']);

if ($this->readConfigEnabled('scheduler', $container, $config['scheduler'])) {
if (!$messengerEnabled) {
throw new LogicException('Scheduler support cannot be enabled as the Messenger component is not '.(interface_exists(MessageBusInterface::class) ? 'enabled.' : 'installed. Try running "composer require symfony/messenger".'));
}
$this->registerSchedulerConfiguration($config['scheduler'], $container, $loader);
}

// messenger depends on validation being registered
if ($this->readConfigEnabled('messenger', $container, $config['messenger'])) {
$this->registerMessengerConfiguration($config['messenger'], $container, $loader, $config['validation']);
if ($messengerEnabled) {
$this->registerMessengerConfiguration($config['messenger'], $container, $loader, $this->readConfigEnabled('validation', $container, $config['validation']));
} else {
$container->removeDefinition('console.command.messenger_consume_messages');
$container->removeDefinition('console.command.messenger_stats');
Expand Down Expand Up @@ -706,10 +717,12 @@ public function load(array $configs, ContainerBuilder $container)
}
$definition->addTag('messenger.message_handler', $tagAttributes);
});

$container->registerAttributeForAutoconfiguration(AsTargetedValueResolver::class, static function (ChildDefinition $definition, AsTargetedValueResolver $attribute): void {
$definition->addTag('controller.targeted_value_resolver', $attribute->name ? ['name' => $attribute->name] : []);
});
$container->registerAttributeForAutoconfiguration(AsSchedule::class, static function (ChildDefinition $definition, AsSchedule $attribute): void {
$definition->addTag('scheduler.schedule_provider', ['name' => $attribute->name]);
});

if (!$container->getParameter('kernel.debug')) {
// remove tagged iterator argument for resource checkers
Expand Down Expand Up @@ -1995,7 +2008,20 @@ private function registerSemaphoreConfiguration(array $config, ContainerBuilder
}
}

private function registerMessengerConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader, array $validationConfig): void
private function registerSchedulerConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader): void
{
if (!class_exists(SchedulerTransportFactory::class)) {
throw new LogicException('Scheduler support cannot be enabled as the Scheduler component is not installed. Try running "composer require symfony/scheduler".');
}

if (!interface_exists(MessageBusInterface::class)) {
throw new LogicException('Scheduler support cannot be enabled as the Messenger component is not installed. Try running "composer require symfony/messenger".');
}

$loader->load('scheduler.php');
}

private function registerMessengerConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader, bool $validationEnabled): void
{
if (!interface_exists(MessageBusInterface::class)) {
throw new LogicException('Messenger support cannot be enabled as the Messenger component is not installed. Try running "composer require symfony/messenger".');
Expand Down Expand Up @@ -2057,7 +2083,7 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder
}

foreach ($middleware as $middlewareItem) {
if (!$validationConfig['enabled'] && \in_array($middlewareItem['id'], ['validation', 'messenger.middleware.validation'], true)) {
if (!$validationEnabled && \in_array($middlewareItem['id'], ['validation', 'messenger.middleware.validation'], true)) {
throw new LogicException('The Validation middleware is only available when the Validator component is installed and enabled. Try running "composer require symfony/validator".');
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
use Symfony\Component\Mime\DependencyInjection\AddMimeTypeGuesserPass;
use Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoPass;
use Symfony\Component\Routing\DependencyInjection\RoutingResolverPass;
use Symfony\Component\Scheduler\DependencyInjection\AddScheduleMessengerPass;
use Symfony\Component\Serializer\DependencyInjection\SerializerPass;
use Symfony\Component\Translation\DependencyInjection\TranslationDumperPass;
use Symfony\Component\Translation\DependencyInjection\TranslationExtractorPass;
Expand Down Expand Up @@ -165,6 +166,7 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(new TestServiceContainerWeakRefPass(), PassConfig::TYPE_BEFORE_REMOVING, -32);
$container->addCompilerPass(new TestServiceContainerRealRefPass(), PassConfig::TYPE_AFTER_REMOVING);
$this->addCompilerPassIfExists($container, AddMimeTypeGuesserPass::class);
$this->addCompilerPassIfExists($container, AddScheduleMessengerPass::class);
$this->addCompilerPassIfExists($container, MessengerPass::class);
$this->addCompilerPassIfExists($container, HttpClientPass::class);
$this->addCompilerPassIfExists($container, AddAutoMappingConfigurationPass::class);
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@
->private()
->tag('cache.pool')

->set('cache.scheduler')
->parent('cache.app')
->private()
->tag('cache.pool')

->set('cache.adapter.system', AdapterInterface::class)
->abstract()
->factory([AbstractAdapter::class, 'createSystemCache'])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
->tag('serializer.normalizer', ['priority' => -880])

->set('messenger.transport.native_php_serializer', PhpSerializer::class)
->alias('messenger.default_serializer', 'messenger.transport.native_php_serializer')

// Middleware
->set('messenger.middleware.handle_message', HandleMessageMiddleware::class)
Expand Down
25 changes: 25 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/Resources/config/scheduler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Symfony\Component\Scheduler\Messenger\SchedulerTransportFactory;

return static function (ContainerConfigurator $container) {
$container->services()
->set('scheduler.messenger_transport_factory', SchedulerTransportFactory::class)
->args([
tagged_locator('scheduler.schedule_provider', 'name'),
service('clock'),
])
->tag('messenger.transport_factory')
;
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<xsd:element name="validation" type="validation" minOccurs="0" maxOccurs="1" />
<xsd:element name="annotations" type="annotations" minOccurs="0" maxOccurs="1" />
<xsd:element name="property-access" type="property_access" minOccurs="0" maxOccurs="1" />
<xsd:element name="scheduler" type="scheduler" minOccurs="0" maxOccurs="1" />
<xsd:element name="serializer" type="serializer" minOccurs="0" maxOccurs="1" />
<xsd:element name="property-info" type="property_info" minOccurs="0" maxOccurs="1" />
<xsd:element name="cache" type="cache" minOccurs="0" maxOccurs="1" />
Expand Down Expand Up @@ -271,6 +272,10 @@
<xsd:attribute name="throw-exception-on-invalid-property-path" type="xsd:boolean" />
</xsd:complexType>

<xsd:complexType name="scheduler">
<xsd:attribute name="enabled" type="xsd:boolean" />
</xsd:complexType>

<xsd:complexType name="serializer">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="mapping" type="file_mapping" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Notifier\Notifier;
use Symfony\Component\RateLimiter\Policy\TokenBucketLimiter;
use Symfony\Component\Scheduler\Messenger\SchedulerTransportFactory;
use Symfony\Component\Uid\Factory\UuidFactory;

class ConfigurationTest extends TestCase
Expand Down Expand Up @@ -687,6 +688,9 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor
'enabled' => !class_exists(FullStack::class) && class_exists(HtmlSanitizer::class),
'sanitizers' => [],
],
'scheduler' => [
'enabled' => !class_exists(FullStack::class) && class_exists(SchedulerTransportFactory::class),
],
'exceptions' => [],
'webhook' => [
'enabled' => false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

$container->loadFromExtension('framework', [
'http_method_override' => false,
'scheduler' => true,
'messenger' => [
'routing' => [
FooMessage::class => ['sender.bar', 'sender.biz'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
'failed' => 'in-memory:///',
'redis' => 'redis://127.0.0.1:6379/messages',
'beanstalkd' => 'beanstalkd://127.0.0.1:11300',
'schedule' => 'schedule://default',
],
],
]);
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">

<framework:config http-method-override="false">
<framework:scheduler enabled="true" />
<framework:messenger>
<framework:routing message-class="Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\FooMessage">
<framework:sender service="sender.bar" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">

<framework:config http-method-override="false">
<framework:messenger>
<framework:transport name="schedule" dsn="schedule://default" />
</framework:messenger>
</framework:config>
</container>
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<framework:transport name="failed" dsn="in-memory:///" />
<framework:transport name="redis" dsn="redis://127.0.0.1:6379/messages" />
<framework:transport name="beanstalkd" dsn="beanstalkd://127.0.0.1:11300" />
<framework:transport name="schedule" dsn="schedule://default" />
</framework:messenger>
</framework:config>
</container>
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
framework:
http_method_override: false
scheduler: true
messenger:
routing:
'Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\FooMessage': ['sender.bar', 'sender.biz']
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
framework:
http_method_override: false
messenger:
transports:
schedule: 'schedule://default'
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ framework:
failed: 'in-memory:///'
redis: 'redis://127.0.0.1:6379/messages'
beanstalkd: 'beanstalkd://127.0.0.1:11300'
schedule: 'schedule://default'
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,13 @@ public function testWebLink()
public function testMessengerServicesRemovedWhenDisabled()
{
$container = $this->createContainerFromFile('messenger_disabled');
$messengerDefinitions = array_filter(
$container->getDefinitions(),
static fn ($name) => str_starts_with($name, 'messenger.'),
\ARRAY_FILTER_USE_KEY
);

$this->assertEmpty($messengerDefinitions);
$this->assertFalse($container->hasDefinition('console.command.messenger_consume_messages'));
$this->assertFalse($container->hasDefinition('console.command.messenger_debug'));
$this->assertFalse($container->hasDefinition('console.command.messenger_stop_workers'));
Expand Down Expand Up @@ -801,14 +808,28 @@ public function testMessengerWithExplictResetOnMessageLegacy()

public function testMessenger()
{
$container = $this->createContainerFromFile('messenger');
$container = $this->createContainerFromFile('messenger', [], true, false);
$container->addCompilerPass(new ResolveTaggedIteratorArgumentPass());
$container->compile();

$expectedFactories = [
new Reference('scheduler.messenger_transport_factory'),
new Reference('messenger.transport.amqp.factory'),
new Reference('messenger.transport.redis.factory'),
new Reference('messenger.transport.sync.factory'),
new Reference('messenger.transport.in_memory.factory'),
new Reference('messenger.transport.sqs.factory'),
new Reference('messenger.transport.beanstalkd.factory'),
];

$this->assertTrue($container->hasDefinition('messenger.receiver_locator'));
$this->assertTrue($container->hasDefinition('console.command.messenger_consume_messages'));
$this->assertTrue($container->hasAlias('messenger.default_bus'));
$this->assertTrue($container->getAlias('messenger.default_bus')->isPublic());
$this->assertTrue($container->hasDefinition('messenger.transport.amqp.factory'));
$this->assertTrue($container->hasDefinition('messenger.transport.redis.factory'));
$this->assertTrue($container->hasDefinition('messenger.transport_factory'));
$this->assertSame(TransportFactory::class, $container->getDefinition('messenger.transport_factory')->getClass());
$this->assertInstanceOf(TaggedIteratorArgument::class, $container->getDefinition('messenger.transport_factory')->getArgument(0));
$this->assertEquals($expectedFactories, $container->getDefinition('messenger.transport_factory')->getArgument(0)->getValues());
$this->assertTrue($container->hasDefinition('messenger.listener.reset_services'));
$this->assertSame('messenger.listener.reset_services', (string) $container->getDefinition('console.command.messenger_consume_messages')->getArgument(5));
}
Expand All @@ -825,10 +846,7 @@ public function testMessengerWithoutConsole()
$this->assertFalse($container->hasDefinition('console.command.messenger_consume_messages'));
$this->assertTrue($container->hasAlias('messenger.default_bus'));
$this->assertTrue($container->getAlias('messenger.default_bus')->isPublic());
$this->assertTrue($container->hasDefinition('messenger.transport.amqp.factory'));
$this->assertTrue($container->hasDefinition('messenger.transport.redis.factory'));
$this->assertTrue($container->hasDefinition('messenger.transport_factory'));
$this->assertSame(TransportFactory::class, $container->getDefinition('messenger.transport_factory')->getClass());
$this->assertFalse($container->hasDefinition('messenger.listener.reset_services'));
}

Expand Down Expand Up @@ -953,6 +971,14 @@ public function testMessengerTransports()

$this->assertTrue($container->hasDefinition('messenger.transport.beanstalkd.factory'));

$this->assertTrue($container->hasDefinition('messenger.transport.schedule'));
$transportFactory = $container->getDefinition('messenger.transport.schedule')->getFactory();
$transportArguments = $container->getDefinition('messenger.transport.schedule')->getArguments();

$this->assertEquals([new Reference('messenger.transport_factory'), 'createTransport'], $transportFactory);
$this->assertCount(3, $transportArguments);
$this->assertSame('schedule://default', $transportArguments[0]);

$this->assertSame(10, $container->getDefinition('messenger.retry.multiplier_retry_strategy.customised')->getArgument(0));
$this->assertSame(7, $container->getDefinition('messenger.retry.multiplier_retry_strategy.customised')->getArgument(1));
$this->assertSame(3, $container->getDefinition('messenger.retry.multiplier_retry_strategy.customised')->getArgument(2));
Expand All @@ -966,6 +992,7 @@ public function testMessengerTransports()
'default' => new Reference('messenger.transport.failed'),
'failed' => new Reference('messenger.transport.failed'),
'redis' => new Reference('messenger.transport.failed'),
'schedule' => new Reference('messenger.transport.failed'),
];

$failureTransportsReferences = array_map(function (ServiceClosureArgument $serviceClosureArgument) {
Expand Down
Loading