Skip to content

How to use SingleStreamStrategy? #40

Open

Description

@enumag

I'm trying to enable SingleStreamStrategy to fix performance issues in projections (see proophsoftware/es-emergency-call#5 for details).

For now I'm unable to get it working. EventStore still makes one stream per aggregate instead of per aggregate type. Here is my current configuration:

services:
    Prooph\EventStore\Pdo\PostgresEventStore:
        arguments: ['@messageFactory', '@eventStoreConnection', '@stream_strategy']

    stream_strategy:
        class: Prooph\EventStore\Pdo\PersistenceStrategy\PostgresSingleStreamStrategy

In the documentation I found a link to this example to initialize the streams. This creates one more stream in the database but the EventStore is still creating new streams for every new aggregate. Also the example is confusing. Shouldn't I create one stream for each aggregate type instead of just one stream?

Activity

  1. changed the title [-]How to use SingleStreamStrategy[/-] [+]How to use SingleStreamStrategy?[/+] on Mar 12, 2018
  2. enumag commented on Mar 12, 2018

    @enumag
    MemberAuthor

    Ok it seems it needs to be configured on each repository definition as well:

    prooph_event_store:
        stores:
            acme_store:
                event_store: Prooph\EventStore\Pdo\MysqlEventStore
                repositories:
                    todo_list:
                        repository_class: Prooph\ProophessorDo\Infrastructure\Repository\EventStoreUserCollection
                        aggregate_type: Prooph\ProophessorDo\Model\User\User
                        aggregate_translator: prooph_event_sourcing.aggregate_translator
                        # I was missing this line.
                        one_stream_per_aggregate: false

    Now however eventstore only uses that one stream I created based on the example script linked above. All events from all aggregate types are mixed in this stream. How can I separate them to one stream per aggregate type?

  3. enumag commented on Mar 12, 2018

    @enumag
    MemberAuthor

    Ok more progress. Looks like I need to override AggregateRepository::determineEventStream with this:

    	protected function determineStreamName(string $aggregateId): StreamName
    	{
    		return new StreamName($this->aggregateType->toString());
    	}

    Now I need to correctly initialize the event streams which means I need to somehow ask prooph for names of all aggregate types that exist throughout the application. How can I do that?

  4. UFOMelkor commented on Mar 12, 2018

    @UFOMelkor
    Member

    @enumag You don't need to overwrite AggregateRepository::determineEventStream.
    It should be enough to set the stream_name in the event-store configuration.

    prooph_event_store:
        stores:
            acme_store:
                event_store: Prooph\EventStore\Pdo\MysqlEventStore
                repositories:
                    todo_list:
                        repository_class: Prooph\ProophessorDo\Infrastructure\Repository\EventStoreUserCollection
                        aggregate_type: Prooph\ProophessorDo\Model\User\User
                        aggregate_translator: prooph_event_sourcing.aggregate_translator
                        one_stream_per_aggregate: false
                        # Set the stream name
                        stream_name: "what-ever-you-want"

    Initializing of the stream is – in my setup – currently part of the database migration. Automation of this sounds tricky. But of course you could get the config of the event store bundle, grab all repositories, filter to get just the one with one stream per aggregate type and create them. I'm just not sure whether this is worth the trouble …

  5. enumag commented on Mar 12, 2018

    @enumag
    MemberAuthor

    @UFOMelkor I didn't realize I need to put that to database migrations. Thanks for pointing it out.

    Well this pretty much resolves this issue for me. But it is probably a good idea to add some notes to the documentation about how to setup the SingleStreamStrategy. As you can see I've spent some time to get it working so it's not exactly clear.

  6. UFOMelkor commented on Mar 12, 2018

    @UFOMelkor
    Member

    Definitely – I will let the issue open for the documentation 👍

  7. webdevilopers commented on Apr 14, 2020

    @webdevilopers

    There is a command by @gquemener that comes with the symfony recipe:

    You can adapt it to your needs e.g.:

    use Prooph\EventStore\EventStore;
    use Prooph\EventStore\Stream;
    use Prooph\EventStore\StreamName;
    use Symfony\Component\Console\Command\Command;
    use Symfony\Component\Console\Input\InputInterface;
    use Symfony\Component\Console\Output\OutputInterface;
    
    final class CreateEventStreamCommand extends Command
    {
        protected static $defaultName = 'acme:create-event-streams';
    
        /** @var EventStore $eventStore */
        private $eventStore;
    
        public function __construct(EventStore $eventStore)
        {
            $this->eventStore = $eventStore;
    
            parent::__construct();
        }
    
        protected function execute(InputInterface $input, OutputInterface $output)
        {
            $this->eventStore->create(new Stream(new StreamName('foo_stream'), new \ArrayIterator()));
            $this->eventStore->create(new Stream(new StreamName('bar_stream'), new \ArrayIterator()));
        }
    }

    And then call it via acme:create-event-streams instead of the original call event-store:event-stream:create.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions