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

allow to configure subscription store #223

Merged
merged 2 commits into from
Nov 30, 2024
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
17 changes: 16 additions & 1 deletion docs/pages/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,22 @@ patchlevel_event_sourcing:

You can find out more about subscriptions in the library
[documentation](https://event-sourcing.patchlevel.io/latest/subscription/).


### Store

You can change where the subscription engine stores its necessary information about the subscription.
Default is `dbal`, which means it stores it in the same DB that is used by the dbal event store.
Otherwise you also have the option to set it to `in_memory`, then this information will not be persisted anywhere.
This is very useful for testing. And if that is not enough, you can also define a `custom` store and specify the service.

```yaml
patchlevel_event_sourcing:
subscription:
store:
type: 'custom' # default is 'dbal'
service: 'my_subscription_store'
```

### Catch Up

If aggregates are used in the processors and new events are generated there,
Expand Down
12 changes: 12 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* @psalm-type Config = array{
* event_bus: array{enabled: bool, type: string, service: string},
* subscription: array{
* store: array{type: string, service: string|null},
* retry_strategy: array{base_delay: int, delay_factor: int, max_attempts: int},
* catch_up: array{enabled: bool, limit: positive-int|null},
* throw_on_error: array{enabled: bool},
Expand Down Expand Up @@ -137,6 +138,17 @@ public function getConfigTreeBuilder(): TreeBuilder
->arrayNode('subscription')
->addDefaultsIfNotSet()
->children()
->arrayNode('store')
->addDefaultsIfNotSet()
->children()
->enumNode('type')
->values(['dbal', 'in_memory', 'custom'])
->defaultValue('dbal')
->end()
->scalarNode('service')->defaultNull()->end()
->end()
->end()

->arrayNode('retry_strategy')
->addDefaultsIfNotSet()
->children()
Expand Down
24 changes: 18 additions & 6 deletions src/DependencyInjection/PatchlevelEventSourcingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
use Patchlevel\EventSourcing\Subscription\RetryStrategy\ClockBasedRetryStrategy;
use Patchlevel\EventSourcing\Subscription\RetryStrategy\RetryStrategy;
use Patchlevel\EventSourcing\Subscription\Store\DoctrineSubscriptionStore;
use Patchlevel\EventSourcing\Subscription\Store\InMemorySubscriptionStore;
use Patchlevel\EventSourcing\Subscription\Store\SubscriptionStore;
use Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver\ArgumentResolver;
use Patchlevel\EventSourcing\Subscription\Subscriber\MetadataSubscriberAccessorRepository;
Expand Down Expand Up @@ -308,13 +309,24 @@ static function (ChildDefinition $definition): void {
$container->register(SubscriberHelper::class)
->setArguments([new Reference(SubscriberMetadataFactory::class)]);

$container->register(DoctrineSubscriptionStore::class)
->setArguments([
new Reference('event_sourcing.dbal_connection'),
])
->addTag('event_sourcing.doctrine_schema_configurator');
if ($config['subscription']['store']['type'] === 'custom') {
if ($config['subscription']['store']['service'] === null) {
throw new InvalidArgumentException('Custom subscription store type requires a service');
}

$container->setAlias(SubscriptionStore::class, DoctrineSubscriptionStore::class);
$container->setAlias(SubscriptionStore::class, $config['subscription']['store']['service']);
} elseif ($config['subscription']['store']['type'] === 'in_memory') {
$container->register(InMemorySubscriptionStore::class);
$container->setAlias(SubscriptionStore::class, InMemorySubscriptionStore::class);
} elseif ($config['subscription']['store']['type'] === 'dbal') {
$container->register(DoctrineSubscriptionStore::class)
->setArguments([
new Reference('event_sourcing.dbal_connection'),
])
->addTag('event_sourcing.doctrine_schema_configurator');

$container->setAlias(SubscriptionStore::class, DoctrineSubscriptionStore::class);
}

$container->registerForAutoconfiguration(ArgumentResolver::class)
->addTag('event_sourcing.argument_resolver');
Expand Down
27 changes: 27 additions & 0 deletions tests/Unit/PatchlevelEventSourcingBundleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
use Patchlevel\EventSourcing\Subscription\Engine\DefaultSubscriptionEngine;
use Patchlevel\EventSourcing\Subscription\Engine\SubscriptionEngine;
use Patchlevel\EventSourcing\Subscription\Repository\RunSubscriptionEngineRepositoryManager;
use Patchlevel\EventSourcing\Subscription\Store\DoctrineSubscriptionStore;
use Patchlevel\EventSourcing\Subscription\Store\InMemorySubscriptionStore;
use Patchlevel\EventSourcing\Subscription\Store\SubscriptionStore;
use Patchlevel\EventSourcing\Subscription\Subscriber\MetadataSubscriberAccessorRepository;
use Patchlevel\EventSourcingBundle\DependencyInjection\PatchlevelEventSourcingExtension;
use Patchlevel\EventSourcingBundle\EventBus\SymfonyEventBus;
Expand Down Expand Up @@ -749,6 +752,29 @@ public function testRunSubscriptionEngineRepositoryManager(): void
$container->get(RepositoryManager::class));
}

public function testSubscriptionEngineInMemoryStore(): void
{
$container = new ContainerBuilder();

$this->compileContainer(
$container,
[
'patchlevel_event_sourcing' => [
'connection' => [
'service' => 'doctrine.dbal.eventstore_connection',
],
'subscription' => [
'store' => [
'type' => 'in_memory'
],
],
],
]
);

self::assertInstanceOf(InMemorySubscriptionStore::class, $container->get(SubscriptionStore::class));
}

public function testCatchUpSubscriptionEngine(): void
{
$container = new ContainerBuilder();
Expand Down Expand Up @@ -954,6 +980,7 @@ public function testFullBuild(): void
self::assertInstanceOf(AggregateRootRegistry::class, $container->get(AggregateRootRegistry::class));
self::assertInstanceOf(RepositoryManager::class, $container->get(RepositoryManager::class));
self::assertInstanceOf(EventRegistry::class, $container->get(EventRegistry::class));
self::assertInstanceOf(DoctrineSubscriptionStore::class, $container->get(SubscriptionStore::class));
}

public function testNamedRepository(): void
Expand Down