Skip to content
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

Add Temporal support #49

Open
wants to merge 16 commits into
base: 2.x
Choose a base branch
from
Open
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
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/vendor
/tests/__cache
/.phpunit.result.cache
.idea
vendor
tests/__cache
.phpunit.result.cache
5 changes: 5 additions & 0 deletions .rr.dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ http:
dir: "public"
forbid: [ ".php", ".htaccess" ]

temporal:
address: localhost:7233
activities:
num_workers: 5

logs:
mode: development
channels:
Expand Down
6 changes: 6 additions & 0 deletions .rr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ logs:
metrics:
level: error

# Uncomment to use temporal integration
# temporal:
# address: localhost:7233
# activities:
# num_workers: 5

# Uncomment to use metrics integration
# rpc:
# listen: tcp://127.0.0.1:6001
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
"spiral/roadrunner-metrics": "^2.0.1",
"mikey179/vfsstream": "^1.6.8",
"pestphp/pest-plugin-expectations": "^1.0",
"symfony/runtime": "^5.3.0"
"symfony/runtime": "^5.3.0",
"temporal/sdk": "^1.0"
},
"conflict": {
"doctrine/doctrine-bundle": "<2.1.1",
Expand Down
22 changes: 9 additions & 13 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Baldinof\RoadRunnerBundle\Command\WorkerCommand;
use Baldinof\RoadRunnerBundle\DependencyInjection\BaldinofRoadRunnerExtension;
use Baldinof\RoadRunnerBundle\Helpers\RPCFactory;
use Baldinof\RoadRunnerBundle\Http\KernelHandler;
Expand All @@ -16,22 +15,22 @@
use Baldinof\RoadRunnerBundle\RoadRunnerBridge\HttpFoundationWorker;
use Baldinof\RoadRunnerBundle\RoadRunnerBridge\HttpFoundationWorkerInterface;
use Baldinof\RoadRunnerBundle\Worker\Dependencies;
use Baldinof\RoadRunnerBundle\Worker\Worker;
use Baldinof\RoadRunnerBundle\Worker\WorkerInterface;
use Baldinof\RoadRunnerBundle\Worker\HttpWorker;
use Psr\Log\LoggerInterface;
use Spiral\Goridge\RPC\RPCInterface;
use Spiral\RoadRunner\Environment;
use Spiral\RoadRunner\EnvironmentInterface;
use Spiral\RoadRunner\Http\HttpWorker;
use Spiral\RoadRunner\Http\HttpWorkerInterface;
use Spiral\RoadRunner\Http\HttpWorker as RoadRunnerHttpWorker;
use Spiral\RoadRunner\Http\HttpWorkerInterface as RoadRunnerHttpWorkerInterface;
use Spiral\RoadRunner\Metrics\Metrics;
use Spiral\RoadRunner\Metrics\MetricsInterface;
use Spiral\RoadRunner\Worker as RoadRunnerWorker;
use Spiral\RoadRunner\WorkerInterface as RoadRunnerWorkerInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use function function_exists;

// Polyfill of the `service()` function introduced in Symfony 5.1 when using older version
if (!\function_exists('Symfony\Component\DependencyInjection\Loader\Configurator\service')) {
if (!function_exists('Symfony\Component\DependencyInjection\Loader\Configurator\service')) {
function service(string $id): ReferenceConfigurator
{
return ref($id);
Expand All @@ -52,7 +51,7 @@ function service(string $id): ReferenceConfigurator
->factory([RoadRunnerWorker::class, 'createFromEnvironment'])
->args([service(EnvironmentInterface::class), '%baldinof_road_runner.intercept_side_effect%']);

$services->set(HttpWorkerInterface::class, HttpWorker::class)
$services->set(RoadRunnerHttpWorkerInterface::class, RoadRunnerHttpWorker::class)
->args([service(RoadRunnerWorkerInterface::class)]);

$services->set(RPCInterface::class)
Expand All @@ -64,11 +63,12 @@ function service(string $id): ReferenceConfigurator

// Bundle services
$services->set(HttpFoundationWorkerInterface::class, HttpFoundationWorker::class)
->args([service(HttpWorkerInterface::class)]);
->args([service(RoadRunnerHttpWorkerInterface::class)]);

$services->set(WorkerInterface::class, Worker::class)
$services->set(HttpWorker::class)
->public() // Manually retrieved on the DIC in the Worker if the kernel has been rebooted
->tag('monolog.logger', ['channel' => BaldinofRoadRunnerExtension::MONOLOG_CHANNEL])
->lazy()
->args([
service('kernel'),
service(LoggerInterface::class),
Expand All @@ -83,10 +83,6 @@ function service(string $id): ReferenceConfigurator
service(EventDispatcherInterface::class),
]);

$services->set(WorkerCommand::class)
->args([service(WorkerInterface::class)])
->autoconfigure();

$services->set(KernelHandler::class)
->args([
service('kernel'),
Expand Down
79 changes: 79 additions & 0 deletions config/services_temporal.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

declare(strict_types=1);

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Baldinof\RoadRunnerBundle\Command\WorkerCommand;
use Baldinof\RoadRunnerBundle\DependencyInjection\BaldinofRoadRunnerExtension;
use Baldinof\RoadRunnerBundle\Worker\HttpWorker;
use Baldinof\RoadRunnerBundle\Worker\TemporalWorker;
use Baldinof\RoadRunnerBundle\Worker\WorkerResolver;
use Baldinof\RoadRunnerBundle\Worker\WorkerResolverInterface;
use Spiral\RoadRunner\EnvironmentInterface;
use Temporal\Client\GRPC\ServiceClient;
use Temporal\Client\WorkflowClient;
use Temporal\Client\WorkflowClientInterface;
use Temporal\Worker\WorkerFactoryInterface;
use Temporal\WorkerFactory;
use function function_exists;

// Polyfill of the `service()` function introduced in Symfony 5.1 when using older version
if (!function_exists('Symfony\Component\DependencyInjection\Loader\Configurator\service')) {
function service(string $id): ReferenceConfigurator
{
return ref($id);
}
}

return static function (ContainerConfigurator $container) {
$container->parameters()
->set('baldinof_road_runner.temporal_address', '127.0.0.1:7233');

$services = $container->services();

$services
->set(WorkerFactoryInterface::class)
->factory([WorkerFactory::class, 'create']);

$services
->set(TemporalWorker::class)
->public() // Manually retrieved on the DIC in the Worker if the kernel has been rebooted
->tag('monolog.logger', ['channel' => BaldinofRoadRunnerExtension::MONOLOG_CHANNEL])
->lazy()
->args([
service('kernel'),
service(WorkerFactoryInterface::class),
tagged_iterator('baldinof_road_runner.temporal_workflows'),
tagged_iterator('baldinof_road_runner.temporal_activities'),
]);

$services
->set(WorkerResolverInterface::class, WorkerResolver::class)
->args([
service(EnvironmentInterface::class),
service(HttpWorker::class),
service(TemporalWorker::class),
]);

$services
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in services.php

->set(WorkerCommand::class)
->args([
service(WorkerResolverInterface::class),
service(EnvironmentInterface::class),
])
->autoconfigure();

$services
->set(WorkflowClientInterface::class, WorkflowClient::class)
->args([
service(ServiceClient::class),
]);

$services
->set(ServiceClient::class)
->factory([ServiceClient::class, 'create'])
->args([
param('baldinof_road_runner.temporal_address')
]);
};
44 changes: 21 additions & 23 deletions src/Command/WorkerCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

namespace Baldinof\RoadRunnerBundle\Command;

use Baldinof\RoadRunnerBundle\Worker\WorkerInterface;
use Spiral\RoadRunner\Environment\Mode;
use Baldinof\RoadRunnerBundle\Exception\UnsupportedRoadRunnerModeException;
use Baldinof\RoadRunnerBundle\Worker\WorkerResolverInterface;
use Spiral\RoadRunner\EnvironmentInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
Expand All @@ -15,57 +16,54 @@ final class WorkerCommand extends Command
{
protected static $defaultName = 'baldinof:roadrunner:worker';

private WorkerInterface $worker;
private WorkerResolverInterface $workerResolver;
private EnvironmentInterface $environment;

public function __construct(WorkerInterface $worker)
public function __construct(
WorkerResolverInterface $workerResolver,
EnvironmentInterface $environment
)
{
parent::__construct();

$this->worker = $worker;
$this->workerResolver = $workerResolver;
$this->environment = $environment;
}

public function configure(): void
{
$this
->setDescription('Run the roadrunner worker')
->setDescription('Run the roadrunner')
->setHelp(<<<EOF
This command should not be run manually but specified in a <info>.rr.yaml</info>
configuration file.
EOF);
}

protected function execute(InputInterface $input, OutputInterface $output)
protected function execute(InputInterface $input, OutputInterface $output): int
{
if (getenv('RR_MODE') !== Mode::MODE_HTTP) {
xepozz marked this conversation as resolved.
Show resolved Hide resolved
try {
$worker = $this->workerResolver->resolve($this->environment->getMode());
} catch (UnsupportedRoadRunnerModeException $e) {
$content = file_get_contents(__DIR__.'/../../.rr.dev.yaml');
Baldinof marked this conversation as resolved.
Show resolved Hide resolved

$io = new SymfonyStyle($input, $output);

$io->title('RoadRunner Bundle');
$io->error('Command baldinof:roadrunner:worker should not be run manually');
$io->writeln('You should reference this command in a <info>.rr.yaml</> configuration file, then run <info>bin/rr serve</>. Example:');
$io->writeln(<<<YAML
<comment>
http:
address: "0.0.0.0:8080"

uploads:
forbid: [".php", ".exe", ".bat"]

workers:
command: "php bin/console baldinof:roadrunner:worker"
relay: "unix://var/roadrunner.sock"

static:
dir: "public"
forbid: [".php", ".htaccess"]
{$content}
</comment>
YAML);

$io->writeln('See <href=https://roadrunner.dev/>RoadRunner</> and <href=https://github.com/Baldinof/roadrunner-bundle/blob/master/README.md>baldinof/roadrunner-bundle</> documentations.');
$io->writeln('See <href=https://roadrunner.dev/>RoadRunner</> and <href=https://github.com/Baldinof/roadrunner-bundle/blob/2.x/README.md>baldinof/roadrunner-bundle</> documentations.');

return 1;
}

$this->worker->start();
$worker->start();

return 0;
}
Expand Down
23 changes: 22 additions & 1 deletion src/DependencyInjection/BaldinofRoadRunnerExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,24 @@
use Baldinof\RoadRunnerBundle\Integration\Symfony\ConfigureVarDumperListener;
use Baldinof\RoadRunnerBundle\Reboot\KernelRebootStrategyInterface;
use Baldinof\RoadRunnerBundle\Reboot\OnExceptionRebootStrategy;
use BlackfireProbe;
use Doctrine\Persistence\ManagerRegistry;
use Psr\Log\LoggerInterface;
use Sentry\State\HubInterface;
use Spiral\RoadRunner\Metrics\Collector;
use Spiral\RoadRunner\Metrics\MetricsInterface;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Temporal\Activity\ActivityInterface;
use Temporal\Client\WorkflowClientInterface;
use Temporal\Workflow\WorkflowInterface;

class BaldinofRoadRunnerExtension extends Extension
{
Expand All @@ -44,6 +49,10 @@ public function load(array $configs, ContainerBuilder $container): void
$loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../../config'));
$loader->load('services.php');

if ($this->isTemporalSdkInstalled()) {
$loader->load('services_temporal.php');
}

if ($container->getParameter('kernel.debug')) {
$this->loadDebug($container);
}
Expand All @@ -56,6 +65,13 @@ public function load(array $configs, ContainerBuilder $container): void

$container->setParameter('baldinof_road_runner.middlewares', $config['middlewares']);

$container->registerAttributeForAutoconfiguration(WorkflowInterface::class, function (ChildDefinition $definition){
$definition->addTag('baldinof_road_runner.temporal_workflows');
});
$container->registerAttributeForAutoconfiguration(ActivityInterface::class, function (ChildDefinition $definition){
$definition->addTag('baldinof_road_runner.temporal_activities');
});

$this->loadIntegrations($container, $config);

if ($config['metrics']['enabled']) {
Expand Down Expand Up @@ -86,7 +102,7 @@ private function loadIntegrations(ContainerBuilder $container, array $config): v
/** @var array */
$bundles = $container->getParameter('kernel.bundles');

if (class_exists(\BlackfireProbe::class)) {
if (class_exists(BlackfireProbe::class)) {
$container->register(BlackfireMiddleware::class);
$beforeMiddlewares[] = BlackfireMiddleware::class;
}
Expand Down Expand Up @@ -149,4 +165,9 @@ private function configureMetrics(array $config, ContainerBuilder $container): v
$listenerDef->addMethodCall('addCollector', [$name, $metric]);
}
}

private function isTemporalSdkInstalled(): bool
{
return interface_exists(WorkflowClientInterface::class);
}
}
13 changes: 13 additions & 0 deletions src/Exception/UnsupportedRoadRunnerModeException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);

namespace Baldinof\RoadRunnerBundle\Exception;

final class UnsupportedRoadRunnerModeException extends \RuntimeException implements ExceptionInterface
{
public function __construct(string $mode)
{
$message = sprintf('Could not resolve worker for mode %s', $mode);
parent::__construct($message);
}
}
Loading