From daa19b0192227e44d7db930ac985c8b9e4ca5c2e Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Wed, 29 Mar 2023 19:30:28 +0300 Subject: [PATCH 1/9] Add interceptors support --- src/Bootloader/TemporalBridgeBootloader.php | 29 ++- src/Commands/MakePresetCommand.php | 7 +- src/Commands/MakeWorkflowCommand.php | 6 +- src/Config/TemporalConfig.php | 38 +++- src/WorkerFactory.php | 111 +++++++++++ src/WorkerFactoryInterface.php | 17 ++ src/WorkersRegistry.php | 16 +- src/Workflow/Workflow.php | 3 + tests/app/src/SomeInterceptor.php | 15 ++ .../TemporalBridgeBootloaderTest.php | 38 +++- tests/src/Config/TemporalConfigTest.php | 20 +- tests/src/WorkerFactoryTest.php | 178 ++++++++++++++++++ 12 files changed, 442 insertions(+), 36 deletions(-) create mode 100644 src/WorkerFactory.php create mode 100644 src/WorkerFactoryInterface.php create mode 100644 tests/app/src/SomeInterceptor.php create mode 100644 tests/src/WorkerFactoryTest.php diff --git a/src/Bootloader/TemporalBridgeBootloader.php b/src/Bootloader/TemporalBridgeBootloader.php index 7c2fb86..91fd8e7 100644 --- a/src/Bootloader/TemporalBridgeBootloader.php +++ b/src/Bootloader/TemporalBridgeBootloader.php @@ -8,7 +8,6 @@ use Spiral\Boot\AbstractKernel; use Spiral\Boot\Bootloader\Bootloader; use Spiral\Boot\EnvironmentInterface; -use Spiral\Boot\FinalizerInterface; use Spiral\Config\ConfiguratorInterface; use Spiral\Config\Patch\Append; use Spiral\Console\Bootloader\ConsoleBootloader; @@ -20,6 +19,8 @@ use Spiral\TemporalBridge\Dispatcher; use Spiral\TemporalBridge\Preset\PresetRegistry; use Spiral\TemporalBridge\Preset\PresetRegistryInterface; +use Spiral\TemporalBridge\WorkerFactory; +use Spiral\TemporalBridge\WorkerFactoryInterface; use Spiral\TemporalBridge\WorkersRegistry; use Spiral\TemporalBridge\WorkersRegistryInterface; use Spiral\TemporalBridge\Workflow\WorkflowManager; @@ -33,22 +34,26 @@ use Temporal\Client\WorkflowClientInterface; use Temporal\DataConverter\DataConverter; use Temporal\DataConverter\DataConverterInterface; +use Temporal\Interceptor\SimplePipelineProvider; +use Temporal\Internal\Interceptor\PipelineProvider; use Temporal\Worker\Transport\Goridge; -use Temporal\Worker\WorkerFactoryInterface; +use Temporal\Worker\WorkerFactoryInterface as TemporalWorkerFactoryInterface; use Temporal\Worker\WorkerOptions; -use Temporal\WorkerFactory; +use Temporal\WorkerFactory as TemporalWorkerFactory; class TemporalBridgeBootloader extends Bootloader { protected const SINGLETONS = [ WorkflowPresetLocatorInterface::class => [self::class, 'initWorkflowPresetLocator'], WorkflowManagerInterface::class => WorkflowManager::class, - WorkerFactoryInterface::class => [self::class, 'initWorkerFactory'], + TemporalWorkerFactoryInterface::class => [self::class, 'initWorkerFactory'], DeclarationLocatorInterface::class => [self::class, 'initDeclarationLocator'], WorkflowClientInterface::class => [self::class, 'initWorkflowClient'], - WorkersRegistryInterface::class => [self::class, 'initWorkersRegistry'], + WorkersRegistryInterface::class => WorkersRegistry::class, PresetRegistryInterface::class => PresetRegistry::class, DataConverterInterface::class => [self::class, 'initDataConverter'], + WorkerFactoryInterface::class => WorkerFactory::class, + PipelineProvider::class => SimplePipelineProvider::class, ]; protected const DEPENDENCIES = [ @@ -99,7 +104,7 @@ protected function initConfig(EnvironmentInterface $env): void [ 'address' => $env->get('TEMPORAL_ADDRESS', '127.0.0.1:7233'), 'namespace' => 'App\\Workflow', - 'defaultWorker' => (string)$env->get('TEMPORAL_TASK_QUEUE', WorkerFactoryInterface::DEFAULT_TASK_QUEUE), + 'defaultWorker' => (string)$env->get('TEMPORAL_TASK_QUEUE', TemporalWorkerFactory::DEFAULT_TASK_QUEUE), 'workers' => [], ] ); @@ -123,8 +128,8 @@ protected function initDataConverter(): DataConverterInterface protected function initWorkerFactory( DataConverterInterface $dataConverter - ): WorkerFactoryInterface { - return new WorkerFactory( + ): TemporalWorkerFactoryInterface { + return new TemporalWorkerFactory( dataConverter: $dataConverter, rpc: Goridge::create() ); @@ -138,12 +143,4 @@ classes: $classes, reader: new AttributeReader() ); } - - protected function initWorkersRegistry( - WorkerFactoryInterface $workerFactory, - FinalizerInterface $finalizer, - TemporalConfig $config - ): WorkersRegistryInterface { - return new WorkersRegistry($workerFactory, $finalizer, $config); - } } diff --git a/src/Commands/MakePresetCommand.php b/src/Commands/MakePresetCommand.php index 82f9f91..7172b56 100644 --- a/src/Commands/MakePresetCommand.php +++ b/src/Commands/MakePresetCommand.php @@ -8,14 +8,19 @@ use Spiral\TemporalBridge\Generator\Generator; use Spiral\TemporalBridge\Preset\PresetRegistryInterface; use Spiral\TemporalBridge\WorkflowPresetLocatorInterface; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Output\OutputInterface; final class MakePresetCommand extends Command { use WithContext; - protected const SIGNATURE = 'temporal:make-preset {preset : Workflow preset} {name : Workflow name}'; + protected const NAME = 'temporal:make-preset'; protected const DESCRIPTION = 'Make a new Temporal workflow preset'; + protected const ARGUMENTS = [ + ['name', InputArgument::REQUIRED, 'Workflow name'], + ['preset', InputArgument::REQUIRED, 'Workflow preset'], + ]; public function perform( Generator $generator, diff --git a/src/Commands/MakeWorkflowCommand.php b/src/Commands/MakeWorkflowCommand.php index 3a7e1c2..5b97bfd 100644 --- a/src/Commands/MakeWorkflowCommand.php +++ b/src/Commands/MakeWorkflowCommand.php @@ -13,14 +13,18 @@ use Spiral\TemporalBridge\Generator\HandlerInterfaceGenerator; use Spiral\TemporalBridge\Generator\WorkflowGenerator; use Spiral\TemporalBridge\Generator\WorkflowInterfaceGenerator; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Output\OutputInterface; final class MakeWorkflowCommand extends Command { use WithContext; - protected const SIGNATURE = 'temporal:make-workflow {name : Workflow name}'; + protected const NAME = 'temporal:make-workflow'; protected const DESCRIPTION = 'Make a new Temporal workflow'; + protected const ARGUMENTS = [ + ['name', InputArgument::REQUIRED, 'Workflow name'], + ]; public function perform(Generator $generator): int { diff --git a/src/Config/TemporalConfig.php b/src/Config/TemporalConfig.php index 3a84343..c3679ba 100644 --- a/src/Config/TemporalConfig.php +++ b/src/Config/TemporalConfig.php @@ -4,10 +4,30 @@ namespace Spiral\TemporalBridge\Config; +use Spiral\Core\Container\Autowire; use Spiral\Core\InjectableConfig; +use Temporal\Exception\ExceptionInterceptorInterface; +use Temporal\Internal\Interceptor\Interceptor; use Temporal\Worker\WorkerFactoryInterface; use Temporal\Worker\WorkerOptions; +/** + * @psalm-type TInterceptor = Interceptor|class-string|Autowire + * @psalm-type TExceptionInterceptor = ExceptionInterceptorInterface|class-string|Autowire + * @psalm-type TWorker = array{ + * options?: WorkerOptions, + * interceptors?: TInterceptor[], + * exception_interceptor?: TExceptionInterceptor + * } + * + * @property array{ + * address: non-empty-string, + * namespace: non-empty-string, + * temporalNamespace: non-empty-string, + * defaultWorker: non-empty-string, + * workers: array + * } $config + */ final class TemporalConfig extends InjectableConfig { public const CONFIG = 'temporal'; @@ -20,29 +40,43 @@ final class TemporalConfig extends InjectableConfig 'workers' => [], ]; + /** + * @return non-empty-string + */ public function getDefaultNamespace(): string { return $this->config['namespace']; } + /** + * @return non-empty-string + */ public function getTemporalNamespace(): string { return $this->config['temporalNamespace']; } + /** + * @return non-empty-string + */ public function getAddress(): string { return $this->config['address']; } + /** + * @return non-empty-string + */ public function getDefaultWorker(): string { return $this->config['defaultWorker']; } - /** @psalm-return array */ + /** + * @return array + */ public function getWorkers(): array { - return (array) $this->config['workers']; + return $this->config['workers'] ?? []; } } diff --git a/src/WorkerFactory.php b/src/WorkerFactory.php new file mode 100644 index 0000000..a2ac072 --- /dev/null +++ b/src/WorkerFactory.php @@ -0,0 +1,111 @@ + */ + private array $workers = []; + + public function __construct( + private readonly TemporalWorkerFactory $workerFactory, + private readonly FinalizerInterface $finalizer, + private readonly FactoryInterface $factory, + private readonly TemporalConfig $config + ) { + $this->workers = $this->config->getWorkers(); + } + + /** + * @param non-empty-string $name + */ + public function create(string $name): WorkerInterface + { + /** @psalm-suppress TooManyArguments */ + $worker = $this->workerFactory->newWorker( + $name, + $this->getWorkerOptions($name), + $this->getExceptionInterceptor($name), + $this->getPipelineProvider($name) + ); + $worker->registerActivityFinalizer(fn() => $this->finalizer->finalize()); + + return $worker; + } + + /** + * @param non-empty-string $name + */ + private function getWorkerOptions(string $name): ?WorkerOptions + { + $worker = $this->workers[$name] ?? null; + + return match (true) { + $worker instanceof WorkerOptions => $worker, + isset($worker['options']) && $worker['options'] instanceof WorkerOptions => $worker['options'], + default => null + }; + } + + /** + * @param non-empty-string $name + */ + private function getExceptionInterceptor(string $name): ?ExceptionInterceptorInterface + { + $worker = $this->workers[$name] ?? null; + if (!\is_array($worker) || !isset($worker['exception_interceptor'])) { + return null; + } + + $exceptionInterceptor = $this->wire($worker['exception_interceptor']); + \assert($exceptionInterceptor instanceof ExceptionInterceptorInterface); + + return $exceptionInterceptor; + } + + /** + * @param non-empty-string $name + */ + private function getPipelineProvider(string $name): ?PipelineProvider + { + $worker = $this->workers[$name] ?? null; + if (!\is_array($worker) || !isset($worker['interceptors'])) { + return null; + } + + $interceptors = []; + foreach ($worker['interceptors'] as $interceptor) { + $interceptor = $this->wire($interceptor); + \assert($interceptor instanceof Interceptor); + + $interceptors[] = $interceptor; + } + + return $this->factory->make(PipelineProvider::class, ['interceptors' => $interceptors]); + } + + private function wire(mixed $alias): object + { + return match (true) { + \is_string($alias) => $this->factory->make($alias), + $alias instanceof Autowire => $alias->resolve($this->factory), + default => $alias + }; + } +} diff --git a/src/WorkerFactoryInterface.php b/src/WorkerFactoryInterface.php new file mode 100644 index 0000000..34aa9c8 --- /dev/null +++ b/src/WorkerFactoryInterface.php @@ -0,0 +1,17 @@ + $options */ public function __construct( - private readonly WorkerFactoryInterface $workerFactory, + private readonly WorkerFactoryInterface|TemporalWorkerFactory $workerFactory, private readonly FinalizerInterface $finalizer, private readonly TemporalConfig $config ) { @@ -34,18 +34,22 @@ public function register(string $name, ?WorkerOptions $options): void ); } - $this->workers[$name] = $this->workerFactory->newWorker($name, $options); - $this->workers[$name]->registerActivityFinalizer(fn() => $this->finalizer->finalize()); + if ($this->workerFactory instanceof WorkerFactoryInterface) { + $this->workers[$name] = $this->workerFactory->create($name); + } else { + $this->workers[$name] = $this->workerFactory->newWorker($name, $options); + $this->workers[$name]->registerActivityFinalizer(fn() => $this->finalizer->finalize()); + } } public function get(string $name): WorkerInterface { \assert($name !== ''); - $options = $this->config->getWorkers(); + $options = $this->config->getWorkers()[$name] ?? null; if (! $this->has($name)) { - $this->register($name, $options[$name] ?? null); + $this->register($name, $options instanceof WorkerOptions ? $options : null); } return $this->workers[$name]; diff --git a/src/Workflow/Workflow.php b/src/Workflow/Workflow.php index 48ef8f7..2f33a5e 100644 --- a/src/Workflow/Workflow.php +++ b/src/Workflow/Workflow.php @@ -44,6 +44,9 @@ public function backoffRetryCoefficient(float $coefficient): self return $this; } + /** + * @param positive-int $attempts + */ public function maxRetryAttempts(int $attempts): self { $this->retryOptions = $this->getRetryOptions() diff --git a/tests/app/src/SomeInterceptor.php b/tests/app/src/SomeInterceptor.php new file mode 100644 index 0000000..ba447ca --- /dev/null +++ b/tests/app/src/SomeInterceptor.php @@ -0,0 +1,15 @@ +assertContainerBoundAsSingleton( WorkflowPresetLocatorInterface::class, @@ -38,7 +42,7 @@ public function testWorkflowPresetLocator() ); } - public function testWorkflowManager() + public function testWorkflowManager(): void { $this->mockContainer(ReaderInterface::class); @@ -48,7 +52,15 @@ public function testWorkflowManager() ); } - public function testWorkerFactory() + public function testTemporalWorkerFactory(): void + { + $this->assertContainerBoundAsSingleton( + TemporalWorkerFactoryInterface::class, + TemporalWorkerFactory::class + ); + } + + public function testWorkerFactory(): void { $this->assertContainerBoundAsSingleton( WorkerFactoryInterface::class, @@ -56,7 +68,7 @@ public function testWorkerFactory() ); } - public function testDataConverter() + public function testDataConverter(): void { $this->assertContainerBoundAsSingleton( DataConverterInterface::class, @@ -64,7 +76,7 @@ public function testDataConverter() ); } - public function testDeclarationLocator() + public function testDeclarationLocator(): void { $this->assertContainerBoundAsSingleton( DeclarationLocatorInterface::class, @@ -72,7 +84,7 @@ public function testDeclarationLocator() ); } - public function testWorkflowClient() + public function testWorkflowClient(): void { $this->assertContainerBoundAsSingleton( WorkflowClientInterface::class, @@ -80,7 +92,7 @@ public function testWorkflowClient() ); } - public function testPresetRegistry() + public function testPresetRegistry(): void { $this->assertContainerBoundAsSingleton( PresetRegistryInterface::class, @@ -96,6 +108,14 @@ public function testWorkersRegistry(): void ); } + public function testPipelineProvider(): void + { + $this->assertContainerBound( + PipelineProvider::class, + SimplePipelineProvider::class + ); + } + public function testAddWorkerOptions(): void { $configs = new ConfigManager($this->createMock(LoaderInterface::class)); diff --git a/tests/src/Config/TemporalConfigTest.php b/tests/src/Config/TemporalConfigTest.php index 6f56142..b9427a1 100644 --- a/tests/src/Config/TemporalConfigTest.php +++ b/tests/src/Config/TemporalConfigTest.php @@ -79,7 +79,25 @@ public function testGetsWorkers(): void { $workers = [ 'first' => WorkerOptions::new(), - 'second' => WorkerOptions::new() + 'second' => WorkerOptions::new(), + 'withOptions' => [ + 'options' => WorkerOptions::new(), + ], + 'withInterceptors' => [ + 'interceptors' => [ + 'foo' + ], + ], + 'withExceptionInterceptor' => [ + 'exception_interceptor' => 'bar' + ], + 'all' => [ + 'options' => WorkerOptions::new(), + 'interceptors' => [ + 'foo' + ], + 'exception_interceptor' => 'bar' + ], ]; $config = new TemporalConfig([ diff --git a/tests/src/WorkerFactoryTest.php b/tests/src/WorkerFactoryTest.php new file mode 100644 index 0000000..33206e8 --- /dev/null +++ b/tests/src/WorkerFactoryTest.php @@ -0,0 +1,178 @@ +temporalWorkerFactory = $this->createMock(TemporalWorkerFactory::class); + } + + public function testCreateWithoutAnyOptions(): void + { + $this->temporalWorkerFactory + ->expects($this->once()) + ->method('newWorker') + ->with('without-any-options') + ->willReturn($worker = $this->createMock(WorkerInterface::class)); + + $factory = $this->createWorkerFactory($this->temporalWorkerFactory); + + $this->assertSame($worker, $factory->create('without-any-options')); + } + + public function testCreateWithOptionsAsValue(): void + { + $this->temporalWorkerFactory + ->expects($this->once()) + ->method('newWorker') + ->with('with-options-as-value', $this->equalTo(WorkerOptions::new()->withEnableSessionWorker())) + ->willReturn($worker = $this->createMock(WorkerInterface::class)); + + $factory = $this->createWorkerFactory($this->temporalWorkerFactory); + + $this->assertSame($worker, $factory->create('with-options-as-value')); + } + + public function testCreateWithOptionsInArray(): void + { + $this->temporalWorkerFactory + ->expects($this->once()) + ->method('newWorker') + ->with('with-options-in-array', $this->equalTo(WorkerOptions::new()->withEnableSessionWorker())) + ->willReturn($worker = $this->createMock(WorkerInterface::class)); + + $factory = $this->createWorkerFactory($this->temporalWorkerFactory); + + $this->assertSame($worker, $factory->create('with-options-in-array')); + } + + /** + * @dataProvider exceptionInterceptorsDataProvider + */ + public function testCreateWithExceptionInterceptor(string $name): void + { + $this->temporalWorkerFactory + ->expects($this->once()) + ->method('newWorker') + ->with($name, null, $this->equalTo(new ExceptionInterceptor([]))) + ->willReturn($worker = $this->createMock(WorkerInterface::class)); + + $factory = $this->createWorkerFactory($this->temporalWorkerFactory); + + $this->assertSame($worker, $factory->create($name)); + } + + public function testCreateWithInterceptors(): void + { + $expectedInterceptors = new SimplePipelineProvider([ + new SomeInterceptor(), + new SomeInterceptor(), + new SomeInterceptor() + ]); + + $this->temporalWorkerFactory + ->expects($this->once()) + ->method('newWorker') + ->with('with-interceptors', null, null, $this->equalTo($expectedInterceptors)) + ->willReturn($worker = $this->createMock(WorkerInterface::class)); + + $factory = $this->createWorkerFactory($this->temporalWorkerFactory); + + $this->assertSame($worker, $factory->create('with-interceptors')); + } + + public function testCreateWithAllOptions(): void + { + $expectedInterceptors = new SimplePipelineProvider([ + new SomeInterceptor(), + new SomeInterceptor(), + new SomeInterceptor() + ]); + + $this->temporalWorkerFactory + ->expects($this->once()) + ->method('newWorker') + ->with( + 'all', + $this->equalTo(WorkerOptions::new()->withEnableSessionWorker()), + $this->equalTo(new ExceptionInterceptor([])), + $this->equalTo($expectedInterceptors) + ) + ->willReturn($worker = $this->createMock(WorkerInterface::class)); + + $factory = $this->createWorkerFactory($this->temporalWorkerFactory); + + $this->assertSame($worker, $factory->create('all')); + } + + public function exceptionInterceptorsDataProvider(): \Traversable + { + yield ['with-exception-interceptor-as-string']; + yield ['with-exception-interceptor-as-autowire']; + yield ['with-exception-interceptor-as-instance']; + } + + private function createWorkerFactory(TemporalWorkerFactory $workerFactory): WorkerFactory + { + $container = new Container(); + $container->bind(PipelineProvider::class, SimplePipelineProvider::class); + $container->bind(ExceptionInterceptor::class, new ExceptionInterceptor([])); + + $interceptors = [ + SomeInterceptor::class, + new SomeInterceptor(), + new Autowire(SomeInterceptor::class) + ]; + + return new WorkerFactory( + $workerFactory, + $this->createMock(FinalizerInterface::class), + $container, + new TemporalConfig([ + 'workers' => [ + 'with-options-as-value' => WorkerOptions::new()->withEnableSessionWorker(), + 'with-options-in-array' => [ + 'options' => WorkerOptions::new()->withEnableSessionWorker() + ], + 'with-interceptors' => [ + 'interceptors' => $interceptors + ], + 'with-exception-interceptor-as-string' => [ + 'exception_interceptor' => ExceptionInterceptor::class + ], + 'with-exception-interceptor-as-autowire' => [ + 'exception_interceptor' => new Autowire(ExceptionInterceptor::class, []) + ], + 'with-exception-interceptor-as-instance' => [ + 'exception_interceptor' => new ExceptionInterceptor([]) + ], + 'all' => [ + 'options' => WorkerOptions::new()->withEnableSessionWorker(), + 'interceptors' => $interceptors, + 'exception_interceptor' => ExceptionInterceptor::class + ] + ] + ]) + ); + } +} From b62167dfe2164fa93b17c5b67cf7b5fa0d8430b1 Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Wed, 29 Mar 2023 19:35:52 +0300 Subject: [PATCH 2/9] Update actions --- .github/workflows/phpunit.yml | 2 ++ .github/workflows/psalm.yml | 2 ++ .github/workflows/run-tests.yml | 11 ++++++----- .github/workflows/static-analysis.yml | 7 +++++++ 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index c592f27..c3d5a51 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -1,7 +1,9 @@ on: + pull_request: null push: branches: - master + - 2.0 name: phpunit diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index 75c416b..6b8698e 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -1,7 +1,9 @@ on: + pull_request: null push: branches: - master + - 2.0 name: static analysis diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 4ed5332..dfa5872 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -1,10 +1,11 @@ -name: run-tests - on: + pull_request: null push: - branches: [ master ] - pull_request: - branches: [ master ] + branches: + - master + - 2.0 + +name: run-tests jobs: test: diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 1a2083b..99d499d 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -1,3 +1,10 @@ +on: + pull_request: null + push: + branches: + - master + - 2.0 + name: run-tests on: From fc08ba5394da9c79329a429666c45c626eac5d85 Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Thu, 30 Mar 2023 13:12:26 +0300 Subject: [PATCH 3/9] Add extensions to the phpunit.yml --- .github/workflows/phpunit.yml | 29 +++++++------- .github/workflows/psalm.yml | 24 +++++------ .github/workflows/static-analysis.yml | 58 --------------------------- 3 files changed, 27 insertions(+), 84 deletions(-) delete mode 100644 .github/workflows/static-analysis.yml diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index c3d5a51..caff662 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -1,19 +1,20 @@ on: - pull_request: null - push: - branches: - - master - - 2.0 + pull_request: null + push: + branches: + - master + - '*.*' name: phpunit jobs: - phpunit: - uses: spiral/gh-actions/.github/workflows/phpunit.yml@master - with: - os: >- - ['ubuntu-latest'] - php: >- - ['8.1', '8.2'] - stability: >- - ['prefer-stable'] + phpunit: + uses: spiral/gh-actions/.github/workflows/phpunit.yml@master + with: + extensions: sockets, grpc + os: >- + ['ubuntu-latest'] + php: >- + ['8.1', '8.2'] + stability: >- + ['prefer-stable'] diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index 6b8698e..96e14a6 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -1,17 +1,17 @@ on: - pull_request: null - push: - branches: - - master - - 2.0 + pull_request: null + push: + branches: + - master + - '*.*' name: static analysis jobs: - psalm: - uses: spiral/gh-actions/.github/workflows/psalm.yml@master - with: - os: >- - ['ubuntu-latest'] - php: >- - ['8.1'] + psalm: + uses: spiral/gh-actions/.github/workflows/psalm.yml@master + with: + os: >- + ['ubuntu-latest'] + php: >- + ['8.1'] diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml deleted file mode 100644 index 99d499d..0000000 --- a/.github/workflows/static-analysis.yml +++ /dev/null @@ -1,58 +0,0 @@ -on: - pull_request: null - push: - branches: - - master - - 2.0 - -name: run-tests - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - static-analysis: - name: Psalm - runs-on: ${{ matrix.os }} - - strategy: - fail-fast: false - matrix: - php: [ 8.0 ] - os: [ ubuntu-latest ] - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - - - name: Validate Composer - run: composer validate - - - name: Get Composer Cache Directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Restore Composer Cache - uses: actions/cache@v3.2.6 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-${{ matrix.php }}-composer - - - name: Install Dependencies - uses: nick-invision/retry@v2.8.3 - with: - timeout_minutes: 5 - max_attempts: 5 - command: composer update --prefer-dist --no-interaction --no-progress - - - name: Static Analysis - run: vendor/bin/psalm --no-cache From ec5f874903076cb7dc66d84e209a19d7edaf4e86 Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Thu, 30 Mar 2023 13:46:20 +0300 Subject: [PATCH 4/9] Temporarily change actions branch --- .github/workflows/phpunit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index caff662..eaed375 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -9,7 +9,7 @@ name: phpunit jobs: phpunit: - uses: spiral/gh-actions/.github/workflows/phpunit.yml@master + uses: spiral/gh-actions/.github/workflows/phpunit.yml@extensions with: extensions: sockets, grpc os: >- From fc701ba53dde5b96f49cf005248aca25cdee31c5 Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Thu, 30 Mar 2023 13:57:38 +0300 Subject: [PATCH 5/9] Revert actions branch, remove duplicated phpunit workflow --- .github/workflows/phpunit.yml | 2 +- .github/workflows/run-tests.yml | 55 --------------------------------- 2 files changed, 1 insertion(+), 56 deletions(-) delete mode 100644 .github/workflows/run-tests.yml diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index eaed375..caff662 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -9,7 +9,7 @@ name: phpunit jobs: phpunit: - uses: spiral/gh-actions/.github/workflows/phpunit.yml@extensions + uses: spiral/gh-actions/.github/workflows/phpunit.yml@master with: extensions: sockets, grpc os: >- diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml deleted file mode 100644 index dfa5872..0000000 --- a/.github/workflows/run-tests.yml +++ /dev/null @@ -1,55 +0,0 @@ -on: - pull_request: null - push: - branches: - - master - - 2.0 - -name: run-tests - -jobs: - test: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: true - matrix: - os: [ ubuntu-latest ] - php: [ 8.0, 8.1 ] - stability: [ prefer-lowest, prefer-stable ] - - name: P${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }} - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - extensions: sockets, grpc - coverage: none - - - name: Validate Composer - run: composer validate - - - name: Get Composer Cache Directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Restore Composer Cache - uses: actions/cache@v3.2.6 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-${{ matrix.php }}-${{ matrix.stability }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-${{ matrix.php }}-${{ matrix.stability }}-composer - - - name: Install Dependencies - uses: nick-invision/retry@v2.8.3 - with: - timeout_minutes: 5 - max_attempts: 5 - command: composer update --prefer-dist --no-interaction --no-progress - - - name: Execute tests - run: vendor/bin/phpunit From 2def9d1ee9517138307e86ee2803a35777cedebb Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Mon, 24 Apr 2023 12:54:17 +0300 Subject: [PATCH 6/9] Change PipelineProvider namespace --- .github/workflows/run-tests.yml | 0 .github/workflows/static-analysis.yml | 0 composer.json | 2 +- src/Bootloader/TemporalBridgeBootloader.php | 2 +- src/WorkerFactory.php | 2 +- tests/src/Bootloader/TemporalBridgeBootloaderTest.php | 2 +- tests/src/WorkerFactoryTest.php | 2 +- 7 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 .github/workflows/run-tests.yml delete mode 100644 .github/workflows/static-analysis.yml diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml deleted file mode 100644 index e69de29..0000000 diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml deleted file mode 100644 index e69de29..0000000 diff --git a/composer.json b/composer.json index a7c158f..d463880 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "spiral/tokenizer": "^3.0", "spiral/roadrunner-bridge": "^2.0 || ^3.0", "nette/php-generator": "^4.0", - "temporal/sdk": "^1.3 || ^2.0" + "temporal/sdk": "dev-interceptors" }, "require-dev": { "spiral/framework": "^3.0", diff --git a/src/Bootloader/TemporalBridgeBootloader.php b/src/Bootloader/TemporalBridgeBootloader.php index 91fd8e7..09429ed 100644 --- a/src/Bootloader/TemporalBridgeBootloader.php +++ b/src/Bootloader/TemporalBridgeBootloader.php @@ -35,7 +35,7 @@ use Temporal\DataConverter\DataConverter; use Temporal\DataConverter\DataConverterInterface; use Temporal\Interceptor\SimplePipelineProvider; -use Temporal\Internal\Interceptor\PipelineProvider; +use Temporal\Interceptor\PipelineProvider; use Temporal\Worker\Transport\Goridge; use Temporal\Worker\WorkerFactoryInterface as TemporalWorkerFactoryInterface; use Temporal\Worker\WorkerOptions; diff --git a/src/WorkerFactory.php b/src/WorkerFactory.php index a2ac072..c21f757 100644 --- a/src/WorkerFactory.php +++ b/src/WorkerFactory.php @@ -10,7 +10,7 @@ use Spiral\TemporalBridge\Config\TemporalConfig; use Temporal\Exception\ExceptionInterceptorInterface; use Temporal\Internal\Interceptor\Interceptor; -use Temporal\Internal\Interceptor\PipelineProvider; +use Temporal\Interceptor\PipelineProvider; use Temporal\Worker\WorkerInterface; use Temporal\Worker\WorkerFactoryInterface as TemporalWorkerFactory; use Temporal\Worker\WorkerOptions; diff --git a/tests/src/Bootloader/TemporalBridgeBootloaderTest.php b/tests/src/Bootloader/TemporalBridgeBootloaderTest.php index 3cb7349..fb0f467 100644 --- a/tests/src/Bootloader/TemporalBridgeBootloaderTest.php +++ b/tests/src/Bootloader/TemporalBridgeBootloaderTest.php @@ -27,7 +27,7 @@ use Temporal\DataConverter\DataConverter; use Temporal\DataConverter\DataConverterInterface; use Temporal\Interceptor\SimplePipelineProvider; -use Temporal\Internal\Interceptor\PipelineProvider; +use Temporal\Interceptor\PipelineProvider; use Temporal\Worker\WorkerFactoryInterface as TemporalWorkerFactoryInterface; use Temporal\Worker\WorkerOptions; use Temporal\WorkerFactory as TemporalWorkerFactory; diff --git a/tests/src/WorkerFactoryTest.php b/tests/src/WorkerFactoryTest.php index 33206e8..6acc5fa 100644 --- a/tests/src/WorkerFactoryTest.php +++ b/tests/src/WorkerFactoryTest.php @@ -13,7 +13,7 @@ use Spiral\TemporalBridge\WorkerFactory; use Temporal\Exception\ExceptionInterceptor; use Temporal\Interceptor\SimplePipelineProvider; -use Temporal\Internal\Interceptor\PipelineProvider; +use Temporal\Interceptor\PipelineProvider; use Temporal\Worker\WorkerFactoryInterface as TemporalWorkerFactory; use Temporal\Worker\WorkerInterface; use Temporal\Worker\WorkerOptions; From a71b80d5f5f2542538ea0b9554d4e698a5fafc84 Mon Sep 17 00:00:00 2001 From: butschster Date: Tue, 25 Apr 2023 10:58:30 +0400 Subject: [PATCH 7/9] Fixes interceptors support for Workflow client. --- .gitignore | 1 + src/Bootloader/PrototypeBootloader.php | 2 +- src/Bootloader/TemporalBridgeBootloader.php | 44 +++++++++++++++------ src/Config/TemporalConfig.php | 13 +++++- src/WorkerFactory.php | 31 +++------------ src/Workflow/Workflow.php | 1 - tests/src/WorkerFactoryTest.php | 38 ++++++++++-------- 7 files changed, 71 insertions(+), 59 deletions(-) diff --git a/.gitignore b/.gitignore index 1a6ed30..29387cb 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ docs vendor node_modules .php-cs-fixer.cache +tests/runtime diff --git a/src/Bootloader/PrototypeBootloader.php b/src/Bootloader/PrototypeBootloader.php index 734ad93..7e93db2 100644 --- a/src/Bootloader/PrototypeBootloader.php +++ b/src/Bootloader/PrototypeBootloader.php @@ -9,7 +9,7 @@ use Spiral\TemporalBridge\WorkflowManagerInterface; use Temporal\Client\WorkflowClientInterface; -class PrototypeBootloader extends Bootloader +final class PrototypeBootloader extends Bootloader { protected const DEPENDENCIES = [ BasePrototypeBootloader::class, diff --git a/src/Bootloader/TemporalBridgeBootloader.php b/src/Bootloader/TemporalBridgeBootloader.php index 09429ed..5e6a79e 100644 --- a/src/Bootloader/TemporalBridgeBootloader.php +++ b/src/Bootloader/TemporalBridgeBootloader.php @@ -11,10 +11,12 @@ use Spiral\Config\ConfiguratorInterface; use Spiral\Config\Patch\Append; use Spiral\Console\Bootloader\ConsoleBootloader; +use Spiral\Core\Container\Autowire; use Spiral\Core\FactoryInterface; use Spiral\RoadRunnerBridge\Bootloader\RoadRunnerBootloader; use Spiral\TemporalBridge\Commands; use Spiral\TemporalBridge\Config\TemporalConfig; +use Spiral\TemporalBridge\DeclarationLocator; use Spiral\TemporalBridge\DeclarationLocatorInterface; use Spiral\TemporalBridge\Dispatcher; use Spiral\TemporalBridge\Preset\PresetRegistry; @@ -34,8 +36,9 @@ use Temporal\Client\WorkflowClientInterface; use Temporal\DataConverter\DataConverter; use Temporal\DataConverter\DataConverterInterface; -use Temporal\Interceptor\SimplePipelineProvider; use Temporal\Interceptor\PipelineProvider; +use Temporal\Interceptor\SimplePipelineProvider; +use Temporal\Internal\Interceptor\Interceptor; use Temporal\Worker\Transport\Goridge; use Temporal\Worker\WorkerFactoryInterface as TemporalWorkerFactoryInterface; use Temporal\Worker\WorkerOptions; @@ -53,7 +56,7 @@ class TemporalBridgeBootloader extends Bootloader PresetRegistryInterface::class => PresetRegistry::class, DataConverterInterface::class => [self::class, 'initDataConverter'], WorkerFactoryInterface::class => WorkerFactory::class, - PipelineProvider::class => SimplePipelineProvider::class, + PipelineProvider::class => [self::class, 'initPipelineProvider'], ]; protected const DEPENDENCIES = [ @@ -62,7 +65,7 @@ class TemporalBridgeBootloader extends Bootloader ]; public function __construct( - private readonly ConfiguratorInterface $config + private readonly ConfiguratorInterface $config, ) { } @@ -70,7 +73,7 @@ public function init( AbstractKernel $kernel, EnvironmentInterface $env, ConsoleBootloader $console, - FactoryInterface $factory + FactoryInterface $factory, ): void { $this->initConfig($env); @@ -88,7 +91,7 @@ public function addWorkerOptions(string $worker, WorkerOptions $options): void protected function initWorkflowPresetLocator( FactoryInterface $factory, - ClassesInterface $classes + ClassesInterface $classes, ): WorkflowPresetLocatorInterface { return new WorkflowPresetLocator( factory: $factory, @@ -106,18 +109,20 @@ protected function initConfig(EnvironmentInterface $env): void 'namespace' => 'App\\Workflow', 'defaultWorker' => (string)$env->get('TEMPORAL_TASK_QUEUE', TemporalWorkerFactory::DEFAULT_TASK_QUEUE), 'workers' => [], - ] + ], ); } protected function initWorkflowClient( TemporalConfig $config, - DataConverterInterface $dataConverter + DataConverterInterface $dataConverter, + PipelineProvider $pipelineProvider, ): WorkflowClientInterface { - return WorkflowClient::create( + return new WorkflowClient( serviceClient: ServiceClient::create($config->getAddress()), options: (new ClientOptions())->withNamespace($config->getTemporalNamespace()), - converter: $dataConverter + converter: $dataConverter, + interceptorProvider: $pipelineProvider, ); } @@ -127,7 +132,7 @@ protected function initDataConverter(): DataConverterInterface } protected function initWorkerFactory( - DataConverterInterface $dataConverter + DataConverterInterface $dataConverter, ): TemporalWorkerFactoryInterface { return new TemporalWorkerFactory( dataConverter: $dataConverter, @@ -136,11 +141,26 @@ protected function initWorkerFactory( } protected function initDeclarationLocator( - ClassesInterface $classes + ClassesInterface $classes, ): DeclarationLocatorInterface { - return new \Spiral\TemporalBridge\DeclarationLocator( + return new DeclarationLocator( classes: $classes, reader: new AttributeReader() ); } + + protected function initPipelineProvider(TemporalConfig $config, FactoryInterface $factory): PipelineProvider + { + /** @var Interceptor[] $interceptors */ + $interceptors = \array_map( + static fn (mixed $interceptor) => match (true) { + \is_string($interceptor) => $factory->make($interceptor), + $interceptor instanceof Autowire => $interceptor->resolve($factory), + default => $interceptor + }, + $config->getInterceptors(), + ); + + return new SimplePipelineProvider($interceptors); + } } diff --git a/src/Config/TemporalConfig.php b/src/Config/TemporalConfig.php index c3679ba..683a941 100644 --- a/src/Config/TemporalConfig.php +++ b/src/Config/TemporalConfig.php @@ -16,7 +16,6 @@ * @psalm-type TExceptionInterceptor = ExceptionInterceptorInterface|class-string|Autowire * @psalm-type TWorker = array{ * options?: WorkerOptions, - * interceptors?: TInterceptor[], * exception_interceptor?: TExceptionInterceptor * } * @@ -25,7 +24,8 @@ * namespace: non-empty-string, * temporalNamespace: non-empty-string, * defaultWorker: non-empty-string, - * workers: array + * workers: array, + * interceptors?: TInterceptor[] * } $config */ final class TemporalConfig extends InjectableConfig @@ -38,6 +38,7 @@ final class TemporalConfig extends InjectableConfig 'temporalNamespace' => 'default', 'defaultWorker' => WorkerFactoryInterface::DEFAULT_TASK_QUEUE, 'workers' => [], + 'interceptors' => [], ]; /** @@ -79,4 +80,12 @@ public function getWorkers(): array { return $this->config['workers'] ?? []; } + + /** + * @return TInterceptor[] + */ + public function getInterceptors(): array + { + return $this->config['interceptors'] ?? []; + } } diff --git a/src/WorkerFactory.php b/src/WorkerFactory.php index c21f757..f9ec100 100644 --- a/src/WorkerFactory.php +++ b/src/WorkerFactory.php @@ -9,10 +9,9 @@ use Spiral\Core\FactoryInterface; use Spiral\TemporalBridge\Config\TemporalConfig; use Temporal\Exception\ExceptionInterceptorInterface; -use Temporal\Internal\Interceptor\Interceptor; use Temporal\Interceptor\PipelineProvider; -use Temporal\Worker\WorkerInterface; use Temporal\Worker\WorkerFactoryInterface as TemporalWorkerFactory; +use Temporal\Worker\WorkerInterface; use Temporal\Worker\WorkerOptions; /** @@ -27,7 +26,8 @@ public function __construct( private readonly TemporalWorkerFactory $workerFactory, private readonly FinalizerInterface $finalizer, private readonly FactoryInterface $factory, - private readonly TemporalConfig $config + private readonly PipelineProvider $pipelineProvider, + private readonly TemporalConfig $config, ) { $this->workers = $this->config->getWorkers(); } @@ -42,9 +42,9 @@ public function create(string $name): WorkerInterface $name, $this->getWorkerOptions($name), $this->getExceptionInterceptor($name), - $this->getPipelineProvider($name) + $this->pipelineProvider, ); - $worker->registerActivityFinalizer(fn() => $this->finalizer->finalize()); + $worker->registerActivityFinalizer(fn () => $this->finalizer->finalize()); return $worker; } @@ -79,27 +79,6 @@ private function getExceptionInterceptor(string $name): ?ExceptionInterceptorInt return $exceptionInterceptor; } - /** - * @param non-empty-string $name - */ - private function getPipelineProvider(string $name): ?PipelineProvider - { - $worker = $this->workers[$name] ?? null; - if (!\is_array($worker) || !isset($worker['interceptors'])) { - return null; - } - - $interceptors = []; - foreach ($worker['interceptors'] as $interceptor) { - $interceptor = $this->wire($interceptor); - \assert($interceptor instanceof Interceptor); - - $interceptors[] = $interceptor; - } - - return $this->factory->make(PipelineProvider::class, ['interceptors' => $interceptors]); - } - private function wire(mixed $alias): object { return match (true) { diff --git a/src/Workflow/Workflow.php b/src/Workflow/Workflow.php index 2f33a5e..4899167 100644 --- a/src/Workflow/Workflow.php +++ b/src/Workflow/Workflow.php @@ -6,7 +6,6 @@ use Temporal\Client\WorkflowClientInterface; use Temporal\Client\WorkflowOptions; -use Temporal\Client\WorkflowStubInterface; use Temporal\Common\RetryOptions; use Temporal\Internal\Client\WorkflowProxy; use Temporal\Internal\Support\DateInterval; diff --git a/tests/src/WorkerFactoryTest.php b/tests/src/WorkerFactoryTest.php index 6acc5fa..813a6e8 100644 --- a/tests/src/WorkerFactoryTest.php +++ b/tests/src/WorkerFactoryTest.php @@ -12,8 +12,8 @@ use Spiral\TemporalBridge\Tests\App\SomeInterceptor; use Spiral\TemporalBridge\WorkerFactory; use Temporal\Exception\ExceptionInterceptor; -use Temporal\Interceptor\SimplePipelineProvider; use Temporal\Interceptor\PipelineProvider; +use Temporal\Interceptor\SimplePipelineProvider; use Temporal\Worker\WorkerFactoryInterface as TemporalWorkerFactory; use Temporal\Worker\WorkerInterface; use Temporal\Worker\WorkerOptions; @@ -87,7 +87,7 @@ public function testCreateWithInterceptors(): void $expectedInterceptors = new SimplePipelineProvider([ new SomeInterceptor(), new SomeInterceptor(), - new SomeInterceptor() + new SomeInterceptor(), ]); $this->temporalWorkerFactory @@ -96,7 +96,7 @@ public function testCreateWithInterceptors(): void ->with('with-interceptors', null, null, $this->equalTo($expectedInterceptors)) ->willReturn($worker = $this->createMock(WorkerInterface::class)); - $factory = $this->createWorkerFactory($this->temporalWorkerFactory); + $factory = $this->createWorkerFactory($this->temporalWorkerFactory, $expectedInterceptors); $this->assertSame($worker, $factory->create('with-interceptors')); } @@ -106,7 +106,7 @@ public function testCreateWithAllOptions(): void $expectedInterceptors = new SimplePipelineProvider([ new SomeInterceptor(), new SomeInterceptor(), - new SomeInterceptor() + new SomeInterceptor(), ]); $this->temporalWorkerFactory @@ -116,11 +116,11 @@ public function testCreateWithAllOptions(): void 'all', $this->equalTo(WorkerOptions::new()->withEnableSessionWorker()), $this->equalTo(new ExceptionInterceptor([])), - $this->equalTo($expectedInterceptors) + $this->equalTo($expectedInterceptors), ) ->willReturn($worker = $this->createMock(WorkerInterface::class)); - $factory = $this->createWorkerFactory($this->temporalWorkerFactory); + $factory = $this->createWorkerFactory($this->temporalWorkerFactory, $expectedInterceptors); $this->assertSame($worker, $factory->create('all')); } @@ -132,8 +132,11 @@ public function exceptionInterceptorsDataProvider(): \Traversable yield ['with-exception-interceptor-as-instance']; } - private function createWorkerFactory(TemporalWorkerFactory $workerFactory): WorkerFactory - { + private function createWorkerFactory( + TemporalWorkerFactory $workerFactory, + PipelineProvider $pipelineProvider = new SimplePipelineProvider(), + ): + WorkerFactory { $container = new Container(); $container->bind(PipelineProvider::class, SimplePipelineProvider::class); $container->bind(ExceptionInterceptor::class, new ExceptionInterceptor([])); @@ -141,37 +144,38 @@ private function createWorkerFactory(TemporalWorkerFactory $workerFactory): Work $interceptors = [ SomeInterceptor::class, new SomeInterceptor(), - new Autowire(SomeInterceptor::class) + new Autowire(SomeInterceptor::class), ]; return new WorkerFactory( $workerFactory, $this->createMock(FinalizerInterface::class), $container, + $pipelineProvider, new TemporalConfig([ 'workers' => [ 'with-options-as-value' => WorkerOptions::new()->withEnableSessionWorker(), 'with-options-in-array' => [ - 'options' => WorkerOptions::new()->withEnableSessionWorker() + 'options' => WorkerOptions::new()->withEnableSessionWorker(), ], 'with-interceptors' => [ - 'interceptors' => $interceptors + 'interceptors' => $interceptors, ], 'with-exception-interceptor-as-string' => [ - 'exception_interceptor' => ExceptionInterceptor::class + 'exception_interceptor' => ExceptionInterceptor::class, ], 'with-exception-interceptor-as-autowire' => [ - 'exception_interceptor' => new Autowire(ExceptionInterceptor::class, []) + 'exception_interceptor' => new Autowire(ExceptionInterceptor::class, []), ], 'with-exception-interceptor-as-instance' => [ - 'exception_interceptor' => new ExceptionInterceptor([]) + 'exception_interceptor' => new ExceptionInterceptor([]), ], 'all' => [ 'options' => WorkerOptions::new()->withEnableSessionWorker(), 'interceptors' => $interceptors, - 'exception_interceptor' => ExceptionInterceptor::class - ] - ] + 'exception_interceptor' => ExceptionInterceptor::class, + ], + ], ]) ); } From 9404e4cbdb63bb52e186e405ad3fb8b57ea83978 Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Fri, 29 Sep 2023 17:15:34 +0300 Subject: [PATCH 8/9] Change temporal/sdk version --- .github/workflows/run-tests.yml | 0 .github/workflows/static-analysis.yml | 0 composer.json | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 .github/workflows/run-tests.yml delete mode 100644 .github/workflows/static-analysis.yml diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml deleted file mode 100644 index e69de29..0000000 diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml deleted file mode 100644 index e69de29..0000000 diff --git a/composer.json b/composer.json index d463880..6443ddf 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "spiral/tokenizer": "^3.0", "spiral/roadrunner-bridge": "^2.0 || ^3.0", "nette/php-generator": "^4.0", - "temporal/sdk": "dev-interceptors" + "temporal/sdk": "^2.7" }, "require-dev": { "spiral/framework": "^3.0", From 2266613a3b2c1f5264fee82ebff694b6d85bc696 Mon Sep 17 00:00:00 2001 From: butschster Date: Mon, 25 Dec 2023 11:28:42 +0400 Subject: [PATCH 9/9] Adds interceptors support --- src/Bootloader/TemporalBridgeBootloader.php | 22 ++++++-------- .../Bootloader/PrototypeBootloaderTest.php | 29 ------------------- .../TemporalBridgeBootloaderTest.php | 20 +++++++++---- 3 files changed, 23 insertions(+), 48 deletions(-) delete mode 100644 tests/src/Bootloader/PrototypeBootloaderTest.php diff --git a/src/Bootloader/TemporalBridgeBootloader.php b/src/Bootloader/TemporalBridgeBootloader.php index b316ebd..126ed46 100644 --- a/src/Bootloader/TemporalBridgeBootloader.php +++ b/src/Bootloader/TemporalBridgeBootloader.php @@ -8,7 +8,6 @@ use Spiral\Boot\AbstractKernel; use Spiral\Boot\Bootloader\Bootloader; use Spiral\Boot\EnvironmentInterface; -use Spiral\Boot\FinalizerInterface; use Spiral\Config\ConfiguratorInterface; use Spiral\Config\Patch\Append; use Spiral\Console\Bootloader\ConsoleBootloader; @@ -20,8 +19,6 @@ use Spiral\TemporalBridge\DeclarationLocator; use Spiral\TemporalBridge\DeclarationLocatorInterface; use Spiral\TemporalBridge\Dispatcher; -use Spiral\TemporalBridge\Preset\PresetRegistry; -use Spiral\TemporalBridge\Preset\PresetRegistryInterface; use Spiral\TemporalBridge\WorkerFactory; use Spiral\TemporalBridge\WorkerFactoryInterface; use Spiral\TemporalBridge\WorkersRegistry; @@ -55,7 +52,8 @@ public function defineDependencies(): array public function defineSingletons(): array { return [ - WorkerFactoryInterface::class => [self::class, 'initWorkerFactory'], + TemporalWorkerFactoryInterface::class => [self::class, 'initWorkerFactory'], + WorkerFactoryInterface::class => WorkerFactory::class, DeclarationLocatorInterface::class => [self::class, 'initDeclarationLocator'], WorkflowClientInterface::class => [self::class, 'initWorkflowClient'], WorkersRegistryInterface::class => WorkersRegistry::class, @@ -91,7 +89,7 @@ protected function initConfig(EnvironmentInterface $env): void [ 'address' => $env->get('TEMPORAL_ADDRESS', '127.0.0.1:7233'), 'namespace' => 'App\\Endpoint\\Temporal\\Workflow', - 'defaultWorker' => (string)$env->get('TEMPORAL_TASK_QUEUE', WorkerFactoryInterface::DEFAULT_TASK_QUEUE), + 'defaultWorker' => (string)$env->get('TEMPORAL_TASK_QUEUE', TemporalWorkerFactoryInterface::DEFAULT_TASK_QUEUE), 'workers' => [], ], ); @@ -115,18 +113,16 @@ protected function initDataConverter(): DataConverterInterface return DataConverter::createDefault(); } - protected function initWorkerFactory( - DataConverterInterface $dataConverter, - ): WorkerFactoryInterface { - return new WorkerFactory( + protected function initWorkerFactory(DataConverterInterface $dataConverter,): TemporalWorkerFactoryInterface + { + return new TemporalWorkerFactory( dataConverter: $dataConverter, rpc: Goridge::create(), ); } - protected function initDeclarationLocator( - ClassesInterface $classes, - ): DeclarationLocatorInterface { + protected function initDeclarationLocator(ClassesInterface $classes,): DeclarationLocatorInterface + { return new DeclarationLocator( classes: $classes, reader: new AttributeReader(), @@ -137,7 +133,7 @@ protected function initPipelineProvider(TemporalConfig $config, FactoryInterface { /** @var Interceptor[] $interceptors */ $interceptors = \array_map( - static fn (mixed $interceptor) => match (true) { + static fn(mixed $interceptor) => match (true) { \is_string($interceptor) => $factory->make($interceptor), $interceptor instanceof Autowire => $interceptor->resolve($factory), default => $interceptor diff --git a/tests/src/Bootloader/PrototypeBootloaderTest.php b/tests/src/Bootloader/PrototypeBootloaderTest.php deleted file mode 100644 index 0d082e7..0000000 --- a/tests/src/Bootloader/PrototypeBootloaderTest.php +++ /dev/null @@ -1,29 +0,0 @@ -getContainer()->get(PrototypeRegistry::class); - - $this->assertInstanceOf( - $expected, - $this->getContainer()->get($registry->resolveProperty($property)->type->name()) - ); - } - - public function propertiesDataProvider(): \Traversable - { - yield [WorkflowClientInterface::class, 'workflow']; - } -} diff --git a/tests/src/Bootloader/TemporalBridgeBootloaderTest.php b/tests/src/Bootloader/TemporalBridgeBootloaderTest.php index 91639f2..7c87d1d 100644 --- a/tests/src/Bootloader/TemporalBridgeBootloaderTest.php +++ b/tests/src/Bootloader/TemporalBridgeBootloaderTest.php @@ -27,6 +27,14 @@ class TemporalBridgeBootloaderTest extends TestCase { + public function testTemporalWorkerFactory(): void + { + $this->assertContainerBoundAsSingleton( + TemporalWorkerFactoryInterface::class, + TemporalWorkerFactory::class, + ); + } + public function testWorkerFactory(): void { $this->assertContainerBoundAsSingleton( @@ -39,7 +47,7 @@ public function testDataConverter(): void { $this->assertContainerBoundAsSingleton( DataConverterInterface::class, - DataConverter::class + DataConverter::class, ); } @@ -47,7 +55,7 @@ public function testDeclarationLocator(): void { $this->assertContainerBoundAsSingleton( DeclarationLocatorInterface::class, - DeclarationLocator::class + DeclarationLocator::class, ); } @@ -55,7 +63,7 @@ public function testWorkflowClient(): void { $this->assertContainerBoundAsSingleton( WorkflowClientInterface::class, - WorkflowClient::class + WorkflowClient::class, ); } @@ -63,7 +71,7 @@ public function testWorkersRegistry(): void { $this->assertContainerBoundAsSingleton( WorkersRegistryInterface::class, - WorkersRegistry::class + WorkersRegistry::class, ); } @@ -71,7 +79,7 @@ public function testPipelineProvider(): void { $this->assertContainerBound( PipelineProvider::class, - SimplePipelineProvider::class + SimplePipelineProvider::class, ); } @@ -86,7 +94,7 @@ public function testAddWorkerOptions(): void $this->assertSame( ['first' => $first, 'second' => $second], - $configs->getConfig(TemporalConfig::CONFIG)['workers'] + $configs->getConfig(TemporalConfig::CONFIG)['workers'], ); } }