Pregunta

Baseline info: I'm using an external OAuth provider for login. If the user logs into the external OAuth, they are OK to enter my system. However this user may not yet exist in my system. It's not really a technology issue, but I'm using JOliver EventStore for what it's worth.

Logic:

  1. I'm not given a guid for new users. I just have an email address.
  2. I check my read model before sending a command, if the user email exists, I issue a Login command with the ID, if not I issue a CreateUser command with a generated ID. My issue is in the case of a new user.
  3. A save occurs in the event store with the new ID.

Issue: Assume two create commands are somehow issued before the read model is updated due to browser refresh or some other anomaly that occurs before consistency with the read model is achieved. That's OK that's not my problem.

What Happens: Because the new ID is a Guid comb, there's no chance the event store will know that these two CreateUser commands represent the same user. By the time they get to the read model, the read model will know (because they have the same email) and can merge the two records or take some other compensating action. But now my read model is out of sync with the event store which still thinks these are two separate entities.

Perhaps it doesn't matter because:

  1. Replaying the events will have the same effect on the read model so that should be OK.
  2. Because both commands are duplicate "Create" commands, they should contain identical information, so it's not like I'm losing anything in the event store.

Can anybody illuminate how they handled similar issues? If some compensating action needs to occur does the read model service issue some kind of compensation command when it realizes it's got a duplicate entry? Is there a simpler methodology I'm not considering?

¿Fue útil?

Solución

You're very close to what I'd consider a proper possible solution. The scenario, if I may summarize, is somewhat like this:

  • Perform the OAuth-entication.
  • Using the read model decide between a recurring visitor and a new visitor, based on the email address.
  • In case of a new visitor, send a RegisterNewVisitor command message that gets handled and stored in the eventstore.
  • Assume there is some concurrency going on that, for the same email address, causes two RegisterNewVisitor messages, each containing what the system thinks is the key associated with the email address. These keys (guids) are different.
  • Detect this duplicate key issue in the read model and merge both read model records into one record.

Now instead of merging the records in the read model, why not send a ResolveDuplicateVisitorEmailAddress { Key1, Key2 } towards your domain model, leaving it up to the domain model (the codified form of the business decision to be taken) to resolve this issue. You could even have a dedicated read model to deal with these kind of issues, the other read model will just get a kind of DuplicateVisitorEmailAddressResolved event, and project it into the proper records.

Word of warning: You've asked a technical question and I gave you a technical, possible solution. In general, I would not apply this technique unless I had some business indicator that this is worth investing in (what's the frequency of a user logging in concurrently for the first time - maybe solving it this way is just a way of ignoring the root cause (flakey OAuth, no register new visitor process in place, etc)). There are other technical solutions to this problem but I wanted to give you the one closest to what you already have in place. They range from registering new visitors sequentially to keeping an in-memory projection of the visitors not yet in the read model.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top