From 9206d2af68b7f9f4474db6320c0a081e29cb62b8 Mon Sep 17 00:00:00 2001 From: Pavel Buchnev Date: Wed, 20 Dec 2023 15:28:59 +0400 Subject: [PATCH] RoadRunner Lock Plugin Integration (#94) Adds RoadRunner lock plugin support --- README.md | 1 + composer.json | 35 +++++++++++++--- src/Bootloader/CacheBootloader.php | 43 ++++++++++--------- src/Bootloader/CentrifugoBootloader.php | 30 +++++++------- src/Bootloader/GRPCBootloader.php | 42 +++++++++++-------- src/Bootloader/HttpBootloader.php | 39 ++++++++++-------- src/Bootloader/LockBootloader.php | 26 ++++++++++++ src/Bootloader/LoggerBootloader.php | 37 +++++++++++------ src/Bootloader/MetricsBootloader.php | 19 +++++---- src/Bootloader/QueueBootloader.php | 55 +++++++++++++------------ src/Bootloader/RoadRunnerBootloader.php | 51 +++++++++++------------ src/Bootloader/ScaffolderBootloader.php | 15 ++++--- src/Bootloader/TcpBootloader.php | 34 ++++++++------- src/Centrifugo/Broadcast.php | 4 +- 14 files changed, 257 insertions(+), 174 deletions(-) create mode 100644 src/Bootloader/LockBootloader.php diff --git a/README.md b/README.md index 16edfec..0971868 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ protected const LOAD = [ RoadRunnerBridge\TcpBootloader::class, // Optional, if it needs to work with TCP plugin RoadRunnerBridge\MetricsBootloader::class, // Optional, if it needs to work with metrics plugin RoadRunnerBridge\LoggerBootloader::class, // Optional, if it needs to work with app-logger plugin + RoadRunnerBridge\LockBootloader::class, // Optional, if it needs to work with lock plugin RoadRunnerBridge\ScaffolderBootloader::class, // Optional, to generate Centrifugo handlers and TCP services via Scaffolder RoadRunnerBridge\CommandBootloader::class, // ... diff --git a/composer.json b/composer.json index 09b1e74..b3f74ab 100644 --- a/composer.json +++ b/composer.json @@ -5,8 +5,11 @@ "license": "MIT", "homepage": "https://spiral.dev", "support": { - "issues": "https://github.com/spiral/framework/issues", - "source": "https://github.com/spiral/roadrunner-bridge" + "issues": "https://github.com/spiral/roadrunner-bridge/issues", + "source": "https://github.com/spiral/roadrunner-bridge", + "docs": "https://spiral.dev/docs", + "forum": "https://forum.spiral.dev", + "chat": "https://discord.gg/V6EK4he" }, "authors": [ { @@ -14,8 +17,16 @@ "email": "wolfy-j@spiralscout.com" }, { - "name": "Pavel Buchnev (butschster)", + "name": "Pavel Butchnev (butschster)", "email": "pavel.buchnev@spiralscout.com" + }, + { + "name": "Aleksei Gagarin (roxblnfk)", + "email": "alexey.gagarin@spiralscout.com" + }, + { + "name": "Maksim Smakouz (msmakouz)", + "email": "maksim.smakouz@spiralscout.com" } ], "require": { @@ -23,7 +34,6 @@ "psr/simple-cache": "^3.0", "psr/http-factory": "^1.0.2", "grpc/grpc": "^1.42", - "roadrunner-php/centrifugo": "^2.0", "spiral/roadrunner-http": "^3.0", "spiral/roadrunner-grpc": "^3.2", "spiral/roadrunner-jobs": "^4.0", @@ -31,16 +41,21 @@ "spiral/roadrunner-tcp": "^3.0", "spiral/roadrunner-metrics": "^3.0", "roadrunner-php/app-logger": "^1.0", - "spiral/framework": "^3.7", + "roadrunner-php/centrifugo": "^2.0", + "roadrunner-php/lock": "^1.0", "spiral/serializer": "^3.7", "spiral/scaffolder": "^3.7" }, "require-dev": { + "spiral/framework": "^3.7", "spiral/testing": "^2.6.1", "phpunit/phpunit": "^10.1", "vimeo/psalm": "^5.0", "spiral/nyholm-bridge": "^1.2" }, + "suggest": { + "ext-protobuf": "For better performance, install the protobuf C extension." + }, "autoload": { "psr-4": { "Spiral\\RoadRunnerBridge\\": "src" @@ -54,6 +69,16 @@ "Spiral\\Tests\\": "tests/src" } }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/roadrunner-server" + } + ], + "scripts": { + "test": "vendor/bin/phpunit", + "psalm": "vendor/bin/psalm --no-cache --config=psalm.xml ./src" + }, "config": { "sort-packages": true, "allow-plugins": { diff --git a/src/Bootloader/CacheBootloader.php b/src/Bootloader/CacheBootloader.php index 2c3b5b6..ac35547 100644 --- a/src/Bootloader/CacheBootloader.php +++ b/src/Bootloader/CacheBootloader.php @@ -15,30 +15,35 @@ final class CacheBootloader extends Bootloader { - protected const DEPENDENCIES = [ - RoadRunnerBootloader::class, - ]; - - protected const SINGLETONS = [ - FactoryInterface::class => [self::class, 'initStorageFactory'], - SerializerInterface::class => DefaultSerializer::class, - ]; - - protected const BINDINGS = [ - StorageInterface::class => [self::class, 'initDefaultStorage'], - ]; + public function defineDependencies(): array + { + return [ + RoadRunnerBootloader::class, + ]; + } - private function initStorageFactory(RPCInterface $rpc, SerializerInterface $serializer): FactoryInterface + public function defineSingletons(): array { - return new Factory($rpc, $serializer); + return [ + FactoryInterface::class => static fn ( + RPCInterface $rpc, + SerializerInterface $serializer, + ): FactoryInterface => new Factory($rpc, $serializer), + + SerializerInterface::class => DefaultSerializer::class, + ]; } - /** - * @param non-empty-string $driver - */ - private function initDefaultStorage(FactoryInterface $factory, string $driver): StorageInterface + public function defineBindings(): array { - return $factory->select($driver); + return [ + StorageInterface::class => + /** @param non-empty-string $driver */ + static fn ( + FactoryInterface $factory, + string $driver, + ): StorageInterface => $factory->select($driver), + ]; } public function init(BaseCacheBootloader $cacheBootloader): void diff --git a/src/Bootloader/CentrifugoBootloader.php b/src/Bootloader/CentrifugoBootloader.php index c683caa..cba851f 100644 --- a/src/Bootloader/CentrifugoBootloader.php +++ b/src/Bootloader/CentrifugoBootloader.php @@ -25,19 +25,22 @@ final class CentrifugoBootloader extends Bootloader { - protected const SINGLETONS = [ - RegistryInterface::class => [self::class, 'initServiceRegistry'], - Interceptor\RegistryInterface::class => [self::class, 'initInterceptorRegistry'], - CentrifugoWorkerInterface::class => CentrifugoWorker::class, - ErrorHandlerInterface::class => LogErrorHandler::class, - CentrifugoApiInterface::class => RPCCentrifugoApi::class, - ]; - public function __construct( private readonly ConfiguratorInterface $config, ) { } + public function defineSingletons(): array + { + return [ + RegistryInterface::class => [self::class, 'initServiceRegistry'], + Interceptor\RegistryInterface::class => [self::class, 'initInterceptorRegistry'], + CentrifugoWorkerInterface::class => CentrifugoWorker::class, + ErrorHandlerInterface::class => LogErrorHandler::class, + CentrifugoApiInterface::class => RPCCentrifugoApi::class, + ]; + } + private function initConfig(): void { $this->config->setDefaults( @@ -49,17 +52,14 @@ private function initConfig(): void ); } - public function init( - BroadcastingBootloader $broadcasting, - ): void { + public function init(BroadcastingBootloader $broadcasting): void + { $this->initConfig(); $broadcasting->registerDriverAlias(Broadcast::class, 'centrifugo'); } - public function boot( - AbstractKernel $kernel, - Dispatcher $dispatcher, - ): void { + public function boot(AbstractKernel $kernel, Dispatcher $dispatcher): void + { $kernel->addDispatcher($dispatcher); } diff --git a/src/Bootloader/GRPCBootloader.php b/src/Bootloader/GRPCBootloader.php index 2d415ae..f374e0a 100644 --- a/src/Bootloader/GRPCBootloader.php +++ b/src/Bootloader/GRPCBootloader.php @@ -33,23 +33,29 @@ final class GRPCBootloader extends Bootloader { - protected const DEPENDENCIES = [ - RoadRunnerBootloader::class, - ]; - - protected const SINGLETONS = [ - Server::class => Server::class, - InvokerInterface::class => [self::class, 'initInvoker'], - LocatorInterface::class => ServiceLocator::class, - ProtoFilesRepositoryInterface::class => [self::class, 'initProtoFilesRepository'], - GeneratorRegistryInterface::class => [self::class, 'initGeneratorRegistry'], - ]; - public function __construct( - private readonly ConfiguratorInterface $config + private readonly ConfiguratorInterface $config, ) { } + public function defineDependencies(): array + { + return [ + RoadRunnerBootloader::class, + ]; + } + + public function defineSingletons(): array + { + return [ + Server::class => Server::class, + InvokerInterface::class => [self::class, 'initInvoker'], + LocatorInterface::class => ServiceLocator::class, + ProtoFilesRepositoryInterface::class => [self::class, 'initProtoFilesRepository'], + GeneratorRegistryInterface::class => [self::class, 'initGeneratorRegistry'], + ]; + } + public function init(): void { $this->initGrpcConfig(); @@ -79,7 +85,7 @@ private function initGrpcConfig(): void ConfigGenerator::class, BootloaderGenerator::class, ], - ] + ], ); } @@ -90,7 +96,7 @@ public function addInterceptor(string|CoreInterceptorInterface|Autowire $interce { $this->config->modify( GRPCConfig::CONFIG, - new Append('interceptors', null, $interceptor) + new Append('interceptors', null, $interceptor), ); } @@ -106,10 +112,10 @@ private function initInvoker( GRPCConfig $config, ContainerInterface $container, FactoryInterface $factory, - BaseInvoker $invoker + BaseInvoker $invoker, ): InvokerInterface { $core = new InterceptableCore( - new InvokerCore($invoker) + new InvokerCore($invoker), ); foreach ($config->getInterceptors() as $interceptor) { @@ -131,7 +137,7 @@ private function initProtoFilesRepository(GRPCConfig $config): ProtoFilesReposit private function initGeneratorRegistry( GRPCConfig $config, ContainerInterface $container, - FactoryInterface $factory + FactoryInterface $factory, ): GeneratorRegistryInterface { $registry = new GeneratorRegistry(); foreach ($config->getGenerators() as $generator) { diff --git a/src/Bootloader/HttpBootloader.php b/src/Bootloader/HttpBootloader.php index 44515b8..2241bad 100644 --- a/src/Bootloader/HttpBootloader.php +++ b/src/Bootloader/HttpBootloader.php @@ -20,28 +20,31 @@ final class HttpBootloader extends Bootloader { - protected const DEPENDENCIES = [ - RoadRunnerBootloader::class, - BaseHttpBootloader::class, - ]; + public function defineDependencies(): array + { + return [ + RoadRunnerBootloader::class, + BaseHttpBootloader::class, + ]; + } - protected const SINGLETONS = [ - ErrorHandlerInterface::class => LogErrorHandler::class, - PSR7Worker::class => PSR7WorkerInterface::class, - PSR7WorkerInterface::class => [self::class, 'initPSR7Worker'], - ]; + public function defineSingletons(): array + { + return [ + ErrorHandlerInterface::class => LogErrorHandler::class, + PSR7Worker::class => PSR7WorkerInterface::class, + + PSR7WorkerInterface::class => static fn ( + WorkerInterface $worker, + ServerRequestFactoryInterface $requests, + StreamFactoryInterface $streams, + UploadedFileFactoryInterface $uploads, + ): PSR7WorkerInterface => new PSR7Worker($worker, $requests, $streams, $uploads), + ]; + } public function boot(KernelInterface $kernel, FactoryInterface $factory): void { $kernel->addDispatcher($factory->make(Dispatcher::class)); } - - private function initPSR7Worker( - WorkerInterface $worker, - ServerRequestFactoryInterface $requests, - StreamFactoryInterface $streams, - UploadedFileFactoryInterface $uploads, - ): PSR7WorkerInterface { - return new PSR7Worker($worker, $requests, $streams, $uploads); - } } diff --git a/src/Bootloader/LockBootloader.php b/src/Bootloader/LockBootloader.php new file mode 100644 index 0000000..fe6d70b --- /dev/null +++ b/src/Bootloader/LockBootloader.php @@ -0,0 +1,26 @@ + Lock::class, + ]; + } +} diff --git a/src/Bootloader/LoggerBootloader.php b/src/Bootloader/LoggerBootloader.php index f1c8496..3564fb0 100644 --- a/src/Bootloader/LoggerBootloader.php +++ b/src/Bootloader/LoggerBootloader.php @@ -14,23 +14,34 @@ final class LoggerBootloader extends Bootloader { - protected const DEPENDENCIES = [ - RoadRunnerBootloader::class, - ]; - - protected const SINGLETONS = [ - Handler::class => [self::class, 'initHandler'], - ]; - - public function init(MonologBootloader $bootloader, Handler $handler): void + public function defineDependencies(): array { - $bootloader->addHandler('roadrunner', $handler); + return [ + RoadRunnerBootloader::class, + ]; } - private function initHandler(Logger $logger, RoadRunnerMode $mode, EnvironmentInterface $env): Handler + public function defineSingletons(): array { - $fallbackHandler = $mode === RoadRunnerMode::Unknown ? new ErrorLogHandler() : null; + return [ + Handler::class => static function ( + Logger $logger, + RoadRunnerMode $mode, + EnvironmentInterface $env, + ): Handler { + $fallbackHandler = $mode === RoadRunnerMode::Unknown ? new ErrorLogHandler() : null; + + return new Handler( + logger: $logger, + fallbackHandler: $fallbackHandler, + formatter: $env->get('LOGGER_FORMAT', Handler::FORMAT), + ); + }, + ]; + } - return new Handler($logger, $fallbackHandler, $env->get('LOGGER_FORMAT', Handler::FORMAT)); + public function init(MonologBootloader $bootloader, Handler $handler): void + { + $bootloader->addHandler('roadrunner', $handler); } } diff --git a/src/Bootloader/MetricsBootloader.php b/src/Bootloader/MetricsBootloader.php index 10ac860..6f12624 100644 --- a/src/Bootloader/MetricsBootloader.php +++ b/src/Bootloader/MetricsBootloader.php @@ -11,16 +11,17 @@ final class MetricsBootloader extends Bootloader { - protected const DEPENDENCIES = [ - RoadRunnerBootloader::class, - ]; - - protected const SINGLETONS = [ - MetricsInterface::class => [self::class, 'initMetrics'], - ]; + public function defineDependencies(): array + { + return [ + RoadRunnerBootloader::class, + ]; + } - protected function initMetrics(RPCInterface $rpc): MetricsInterface + public function defineSingletons(): array { - return new Metrics($rpc); + return [ + MetricsInterface::class => static fn (RPCInterface $rpc): MetricsInterface => new Metrics($rpc), + ]; } } diff --git a/src/Bootloader/QueueBootloader.php b/src/Bootloader/QueueBootloader.php index 413af2c..b4581d6 100644 --- a/src/Bootloader/QueueBootloader.php +++ b/src/Bootloader/QueueBootloader.php @@ -23,39 +23,40 @@ final class QueueBootloader extends Bootloader { - protected const DEPENDENCIES = [ - RoadRunnerBootloader::class, - SerializerBootloader::class, - ]; - - protected const SINGLETONS = [ - ConsumerInterface::class => Consumer::class, - JobsInterface::class => Jobs::class, - QueueConfig::class => [self::class, 'initConfig'], - PipelineRegistryInterface::class => RPCPipelineRegistry::class, - PayloadDeserializerInterface::class => PayloadDeserializer::class, - ]; - - public function init( - BaseQueueBootloader $bootloader, - KernelInterface $kernel, - Dispatcher $jobs, - ): void { - $bootloader->registerDriverAlias(Queue::class, 'roadrunner'); - $kernel->addDispatcher($jobs); + public function defineDependencies(): array + { + return [ + RoadRunnerBootloader::class, + SerializerBootloader::class, + ]; } - public function boot(PipelineRegistryInterface $registry): void + public function defineSingletons(): array { - $registry->declareConsumerPipelines(); + return [ + ConsumerInterface::class => Consumer::class, + JobsInterface::class => Jobs::class, + PipelineRegistryInterface::class => RPCPipelineRegistry::class, + PayloadDeserializerInterface::class => PayloadDeserializer::class, + + QueueConfig::class => static function (ConfigsInterface $configs): QueueConfig { + $config = $configs->getConfig('queue'); + + return new QueueConfig( + $config['pipelines'] ?? [], + ); + }, + ]; } - private function initConfig(ConfigsInterface $configs): QueueConfig + public function init(BaseQueueBootloader $bootloader, KernelInterface $kernel, Dispatcher $jobs): void { - $config = $configs->getConfig('queue'); + $bootloader->registerDriverAlias(Queue::class, 'roadrunner'); + $kernel->addDispatcher($jobs); + } - return new QueueConfig( - $config['pipelines'] ?? [] - ); + public function boot(PipelineRegistryInterface $registry): void + { + $registry->declareConsumerPipelines(); } } diff --git a/src/Bootloader/RoadRunnerBootloader.php b/src/Bootloader/RoadRunnerBootloader.php index d49c6f2..89ccb62 100644 --- a/src/Bootloader/RoadRunnerBootloader.php +++ b/src/Bootloader/RoadRunnerBootloader.php @@ -19,16 +19,29 @@ final class RoadRunnerBootloader extends Bootloader { - protected const SINGLETONS = [ - EnvironmentInterface::class => [self::class, 'initEnvironment'], - Environment::class => EnvironmentInterface::class, - - RPC::class => RPCInterface::class, - RPCInterface::class => [self::class, 'initRPC'], - - Worker::class => WorkerInterface::class, - WorkerInterface::class => [self::class, 'initWorker'], - ]; + public function defineSingletons(): array + { + return [ + EnvironmentInterface::class => static fn ( + GlobalEnvironmentInterface $env, + ): EnvironmentInterface => new Environment($env->getAll()), + + Environment::class => EnvironmentInterface::class, + + RPC::class => RPCInterface::class, + RPCInterface::class => + /** @psalm-suppress ArgumentTypeCoercion */ + static fn ( + EnvironmentInterface $env, + ): RPCInterface => new RPC(Relay::create($env->getRPCAddress())), + + WorkerInterface::class => static fn ( + EnvironmentInterface $env, + ): WorkerInterface => Worker::createFromEnvironment($env), + + Worker::class => WorkerInterface::class, + ]; + } public function init(AbstractKernel $kernel): void { @@ -38,22 +51,4 @@ public function init(AbstractKernel $kernel): void $kernel->addDispatcher($dispatcher); }); } - - private function initEnvironment(GlobalEnvironmentInterface $env): EnvironmentInterface - { - return new Environment($env->getAll()); - } - - /** - * @psalm-suppress ArgumentTypeCoercion - */ - private function initRPC(EnvironmentInterface $env): RPCInterface - { - return new RPC(Relay::create($env->getRPCAddress())); - } - - private function initWorker(EnvironmentInterface $env): WorkerInterface - { - return Worker::createFromEnvironment($env); - } } diff --git a/src/Bootloader/ScaffolderBootloader.php b/src/Bootloader/ScaffolderBootloader.php index 5199386..92de550 100644 --- a/src/Bootloader/ScaffolderBootloader.php +++ b/src/Bootloader/ScaffolderBootloader.php @@ -17,16 +17,19 @@ final class ScaffolderBootloader extends Bootloader { - public const DEPENDENCIES = [ - ConsoleBootloader::class, - BaseScaffolderBootloader::class, - ]; - public function __construct( - private readonly ContainerInterface $container + private readonly ContainerInterface $container, ) { } + public function defineDependencies(): array + { + return [ + ConsoleBootloader::class, + BaseScaffolderBootloader::class, + ]; + } + public function init(BaseScaffolderBootloader $scaffolder, ConsoleBootloader $console): void { $this->configureCommands($console); diff --git a/src/Bootloader/TcpBootloader.php b/src/Bootloader/TcpBootloader.php index ce892d6..f0053da 100644 --- a/src/Bootloader/TcpBootloader.php +++ b/src/Bootloader/TcpBootloader.php @@ -18,21 +18,27 @@ final class TcpBootloader extends Bootloader { - protected const DEPENDENCIES = [ - RoadRunnerBootloader::class, - ]; - - protected const SINGLETONS = [ - Service\RegistryInterface::class => [self::class, 'initServiceRegistry'], - Interceptor\RegistryInterface::class => [self::class, 'initInterceptorRegistry'], - Server::class => Server::class, - ]; - public function __construct( - private readonly ConfiguratorInterface $config + private readonly ConfiguratorInterface $config, ) { } + public function defineDependencies(): array + { + return [ + RoadRunnerBootloader::class, + ]; + } + + public function defineSingletons(): array + { + return [ + Service\RegistryInterface::class => [self::class, 'initServiceRegistry'], + Interceptor\RegistryInterface::class => [self::class, 'initInterceptorRegistry'], + Server::class => Server::class, + ]; + } + public function init(EnvironmentInterface $environment): void { $this->initTcpConfig($environment); @@ -51,20 +57,20 @@ private function initTcpConfig(EnvironmentInterface $environment): void 'services' => [], 'interceptors' => [], 'debug' => $environment->get('TCP_DEBUG', false), - ] + ], ); } private function initInterceptorRegistry( TcpConfig $config, - ContainerInterface $container + ContainerInterface $container, ): Interceptor\RegistryInterface { return new Interceptor\InterceptorRegistry($config->getInterceptors(), $container); } private function initServiceRegistry( TcpConfig $config, - ContainerInterface $container + ContainerInterface $container, ): Service\RegistryInterface { return new Service\ServiceRegistry($config->getServices(), $container); } diff --git a/src/Centrifugo/Broadcast.php b/src/Centrifugo/Broadcast.php index 91479d2..499505c 100644 --- a/src/Centrifugo/Broadcast.php +++ b/src/Centrifugo/Broadcast.php @@ -10,11 +10,11 @@ final class Broadcast extends AbstractBroadcast { public function __construct( - private readonly CentrifugoApiInterface $api + private readonly CentrifugoApiInterface $api, ) { } - public function publish(iterable|\Stringable|string $topics, iterable|string $messages): void + public function publish(iterable|\Stringable|string $topics, iterable|\Stringable|string $messages): void { /** @var non-empty-string[] $topics */ $topics = $this->formatTopics($this->toArray($topics));