Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • Jan 31 2019 19:32

    prolic on v1.10.3

    (compare)

  • Jan 31 2019 19:32

    prolic on master

    update changelog (compare)

  • Jan 31 2019 19:29
    prolic closed #176
  • Jan 31 2019 19:28
    prolic commented #186
  • Jan 31 2019 19:28
    prolic closed #186
  • Jan 31 2019 19:28

    prolic on master

    fix restarting projection durin… respect lock in memory resetting projection and 12 more (compare)

  • Jan 31 2019 16:26
    fritz-gerneth commented #189
  • Jan 31 2019 16:21
    prolic commented #189
  • Jan 31 2019 16:06
    sandrokeil commented #189
  • Jan 31 2019 15:31
    grzegorzstachniukalm synchronize #186
  • Jan 31 2019 15:23
    kamil-nawrotkiewicz edited #76
  • Jan 31 2019 15:22
    kamil-nawrotkiewicz edited #76
  • Jan 31 2019 15:22
    kamil-nawrotkiewicz opened #76
  • Jan 31 2019 15:19
    grzegorzstachniukalm synchronize #186
  • Jan 31 2019 15:09
    grzegorzstachniukalm synchronize #186
  • Jan 31 2019 13:54
    coveralls commented #186
  • Jan 31 2019 13:48
    mrook commented #189
  • Jan 31 2019 13:41
    prolic commented #189
  • Jan 31 2019 13:40
    prolic commented #189
  • Jan 31 2019 13:31
    fritz-gerneth commented #189
Fritz Gerneth
@fritz-gerneth
for us, they don't, one is a projection updating a read model, the other a standaline event listener
Bradley Weston
@bweston92
for example a customer is event sourced but how many times they've clicked a link isn't. The projection is total clicks by a customer. Customer created event (from event sourced) inserts with 0 clicks then clicks from the MQ increment that
Fritz Gerneth
@fritz-gerneth
that'll introduce some serious concurrency pain :)
Bradley Weston
@bweston92
so what would the solution be?
store the events locally?
Fritz Gerneth
@fritz-gerneth
use only one of it I guess
Bradley Weston
@bweston92
the events from the MQ store them in a local event store?
just imagining all the backup and restoration to put in place and test
Fritz Gerneth
@fritz-gerneth
that sounds like you're trying to re-invent ES-replication then (read-instances)
Bradley Weston
@bweston92
doing what I suggested would end up doing that yeah, just trying to think of a way round it all
Fritz Gerneth
@fritz-gerneth
I'd probably try to solve this issue on the ES side, with read-replicas on their side
or split up into different ES instances
Bradley Weston
@bweston92
ok, thanks
MtK
@kochen

Hey all, long time!
I'm designing a small quiz application that has a known structure: Categories, Series & Questions. Categories have 1 or more Series. Series has 1 or more Questions. You could start any Category or multiple and in any order (1, 4, 2, 3), but the Series inside the [started] Category are linear, as well as the Question inside the Series.
Again, for simplicity, we have a known structure.

This logic needs to be kept a bit abstract, in order to allow different "types" of quiz (i.e a single linear series of questions, with other hierarchy or something more complex like "if you answer A your next question is 5").
Scoring rules (for correct or incorrect answers and/or bonus for completion) might change for each instantiated Quiz.

For each user participating in the quiz, we need to store his state/progress including scoring his answers.
We need to be able to mark events such as:

  • Answer Submitted
  • Answer Marked as Correct & Answer Marked as Incorrect to be able to provide the right feedback as the appropriate Score Granted
  • Series Marked as Completed
  • Category Marked as Completed

What is important here is to be able to determine at any moment the "next question" in each series as well as the states of each series (and the next available) & categories.

What I'm struggling a bit with is the modelling of the aggregates here - where would an answer be submitted to, who would the calculate the score (better yet, aggregate the scores) and how to maintain user-progress within the quiz.
For example: Would it make sense to have an QuizState aggregate that gets created when a new Quiz is started by a certain User and is responsible for all the above events? looks a bit too much responsibility, but I can't figure out how to properly split it...

Zacharias
@netiul
Any time soon my first event sourced app goes live 🎉 (Based on event engine). Quite a journey it was, so much new stuff learned, still so much to discover too.
Sascha-Oliver Prolic
@prolic
Congrats @netiul
Greg Szczotka
@greg606

Hello, I have legacy Symfony PSB + PEStore + PESourcing app, in AggregateRoot I have this:

        $this->recordThat(
            BookingWasSettledPartly::into(
                $this->bookingId,
                $newBookingId,
            )
        );

        return $newBooking;

$newBooking is added correctly but this event BookingWasSettledPartly is not, it used to work with older version but now it's not.
What is essential to make it work in this config (PSB+PES+PES)?

Sascha-Oliver Prolic
@prolic
Maybe something simple as using $newBooking instead of $this?
1 reply
Alexander Miertsch
@codeliner
Congrats @netiul
btw. we've integrated prooph board Cody into Event Engine skeleton. You'll find the extended version here: https://github.com/proophboard/php-cody-engine-skeleton
Good catch @prolic ! yeah @greg606 try $newBooking->recordThat(...)
Zacharias
@netiul
Thanks @prolic and @codeliner
This also means I'm currently looking for a new gig. I'm open for any suggestions :)
based in the Netherlands, but can do fully remote
Alexander Miertsch
@codeliner
@netiul wait, you deploy to production and then leave? Now the interesting part would start ....
Zacharias
@netiul
😇
Sascha-Oliver Prolic
@prolic
@netiul sorry man, that is the only guess I have right now. I don't have access to your source code and have it up and running on my local machine. Nor do I want to, lol. If it's hard to figure it out, try isolating the problem in a test-case that fails but you actually would expect to succeed. Then you have at least something at hand that is smaller to debug.
Alexander Miertsch
@codeliner
@prolic you mean @greg606 not @netiul ;)
Greg Szczotka
@greg606
@prolic of course, thanks for useful tips.
MtK
@kochen
@netiul talk to me, I might have something interesting for you...
Zacharias
@netiul
Yes, saw your private message! I'll respond now :)
MtK
@kochen
🤟
Alexander Miertsch
@codeliner
@kochen @netiul :+1:
Mike Milano
@mikemilano
I posted a question too big to ask in this little chat, but if anyone has any guidance, I would appreciate it. I'm pretty excited after going through all the docs, but I am wondering if I need to be thinking about processing delayed data differently, or if there's a way to set back the actual event time. More detail here: https://stackoverflow.com/questions/69861338/is-it-possible-to-set-the-event-created-at-time-with-prooph
Fritz Gerneth
@fritz-gerneth
@mikemilano we did use reflection to set the event date specifically during a migration from a non-ES system to ES. For any production use-case I'd discourage this though as it breaks the time-event-stream (as possibly earlier events occur later). Instead I'd recommend to make the observed date part of your event itself. e.g. differentiate between recorded date and observed date.
Mike Milano
@mikemilano
Thanks @fritz-gerneth , and yeah the event stream would break because I'm fetching delayed data from different sources, which will overlap with each provider I process. Also Thank you to @codeliner for answering in SO!
Sandro Keil
@sandrokeil
If someone faces some memory issues with PDO event store projections, here is a PR prooph/pdo-event-store#234
Alexander Miertsch
@codeliner
you're welcome @mikemilano
Alexander Miertsch
@codeliner
Anyone here with experience to migrate from Travis to Github Actions? Our event store test suite no longer runs on Travis (I guess, they shut down OSS support some time ago)
Sascha-Oliver Prolic
@prolic
I can migrate this, when I have time.
webDEVILopers
@webdevilopers

This is my first implementation of an upcaster. The new event now has a new nullable property spotId. For old events null is added.

final class Upcaster extends SingleEventUpcaster
{
    public function upcast(Message $message): array
    {
        if (! $this->canUpcast($message)) {
            return [$message];
        }

        return $this->doUpcast($message);
    }

    protected function canUpcast(Message $message): bool
    {
        return $message instanceof TestResultReported;
    }

    protected function doUpcast(Message $message): array
    {
        if (array_key_exists('spotId', $message->payload())) {
            return [$message];
        }

        /** @var TestResultReported $message */
        $newMessage = TestResultReported::with(
            $message->testId(),
            $message->placeId(),
            $message->placeName(),
            null,
            false,
            $message->testResult(),
            $message->testType(),
            $message->testedAt(),
            $message->guestId(),
            $message->guestContactInformation(),
            $message->acceptPrivacyPolicy(),
            $message->reportedAt()
        );

        return [$newMessage];
    }
}

Is this the way to go?

Should I add a separate upcaster per event / aggregate root?

Fritz Gerneth
@fritz-gerneth
@webdevilopers I'd follow the pattern of 'do only one thing' - one upcasting transformation. I.e. do not base it on the event but on the transformation.
Sascha-Oliver Prolic
@prolic
As @fritz-gerneth said
webDEVILopers
@webdevilopers

Thanks for the feedback. Could you elaborate on "do not base it on the event"?
For instance use a single upcaster for each transformation?

In our case - using the symfony bundles:

    Prooph\EventStore\Plugin\UpcastingPlugin:
        arguments:
            - '@Trexxon\Common\Infrastructure\Prooph\EventStore\TestResultSpotUpcaster'
            - '@Trexxon\Common\Infrastructure\Prooph\EventStore\TestResultMaybeV2Upcaster'
        tags:
            - { name: 'prooph_event_store.default.plugin' }
Fritz Gerneth
@fritz-gerneth
@webdevilopers yes. i.e. follow / keep the single responsibility pattern: do one thing (transformation). it's not so much a question of for whom you do it (what events) as about what you do it (what kind of transformation)
webDEVILopers
@webdevilopers
Thanks for clearing this up. Sure, following SRP and DDDesign patterns the final "Upcaster" will receive a better naming. :)
webDEVILopers
@webdevilopers

Following this tweet by @gquemener I tried to implement an in-memory read model of a view model:

final class PgsqlEventStorePlaceDetailsFinder
{
    private ProjectionManager $projectionManager;

    public function __construct(ProjectionManager $projectionManager)
    {
        $this->projectionManager = $projectionManager;
    }

    public function detailsOfId(PlaceId $id): Details
    {
        $metadataMatcher = (new MetadataMatcher())
            ->withMetadataMatch('_aggregate_id', Operator::EQUALS(), $id->toString());

        $query = $this->projectionManager->createQuery();
        $query
            ->fromStream('place_stream', $metadataMatcher)
            ->when([
                PlaceAdded::class => function ($state, PlaceAdded $event) {
                    $state = [
                        'accountId'      => $event->accountId()->toString(),
                        'placeId'        => $event->placeId()->toString(),
                        'name'           => $event->name()->toString(),
                        'retentionTime'  => RetentionTime::withDefaultDays()->toDays(),
                        'addedAt'        => $event->createdAt()->format(DATE_ATOM),
                    ];

                    return $state;
                },
                PlaceChanged::class => function ($state, PlaceChanged $event) {
                    $state['name'] = $event->name()->toString();

                    return $state;
                },
            ])
            ->run()
        ;

        $placeState = $query->getState();

        return Details::fromArray($placeState);
    }
}

Thoughts?

Gildas Quéméner
@gquemener
Hello !
I guess that would work.
You could also directly communicate with your event store (which is what the projection manager is most-likely doing) and remove some extra layers : https://github.com/gquemener/repositoring/blob/main/src/Infrastructure/Repository/Prooph/ProophEventStoreTodoRepository.php#L76-L101.
The idea being that in-memory synchronous implementation is enough until you encounter performance issue (I would advise to setup mecanisms to track this issue, if not already done).
The projection manager is reponsible of tracking the position of each projectors, in order to be able to resume projection. As your implementation doesn't use such capability, that's why I suggest to by-pass it.
webDEVILopers
@webdevilopers

You could also directly communicate with your event store

This is an older version of prooph where the query comes from the projection manager.
Here is an example of a newer version:

$eventStore
    ->createQuery()
    ->fromAll()

http://docs.getprooph.org/event-store/standard_projections/overview.html

Is that what you suggested?

Gildas Quéméner
@gquemener

I'm suggesting to inject your Prooph\EventStore\EventStore service into your finder and use EventStore::load directly (check the link I shared for an example), instead of using the projection manager that is aimed to track the status of your projectors.
The reason being that your projector does not need to be tracked, because it reads all the relevant events from the start, every time.

That being said, what you did is probably working fine (however you're adding an unecessary overhead by querying the "projections" table, aren't you?).