2

In a distributed asynchronous system serializability cannot be achieved, but we still have to somehow provide the semantics.

Consider quite natural requirement that user must have unique email or no email at all. (Option of not having an email implies that we cannot use email as a unique actor's address.)

What should happen when system receives two concurrent requests for creating user with same email? One of them should eventually fail.

We could query all user actors asking them whether anyone has same email, but due to concurrency none of the two new users may be created at that time. Same problem exists for email update.

How to achieve these functionality without compromising scalability and performance? How do I let client now that its request failed?

2

The most straight forward approach is probably to distinguish verified emails from unverified emails within your model, and have a single actor responsible for verifying a given email address.

(The simple versions are that you have one actor responsible for verifying all email addresses, or one actor responsible for verifying each email address.)

That gives you parallel creation of users, but serial ordering of the messages those two user actors send to the email verification actors mail box.

(Email is additionally complicated by the fact that your application isn't the book of record for your clients' email addresses; in theory, an email address could be re-assigned without anybody telling you that it happened.)

  • Still, the user creation UI likely requires a synchonous reply as to whether the email is acceptable or not. Consistency must be obtained in real time. – usr Sep 27 '18 at 12:55
1

This is known as set validation.

At some point in time, sooner or later, you will have to serialize this checking, so scalability will be affected for sure. You still get to choose when: before you create the user or after.

  1. Before the user is created

For this you can have a collection in a database with an unique index on the email address. If the insert succeeds then the user is the first with that email address and it will be permitted, otherwise the command is rejected.

The drawback is that the user creation could fail from other reasons and that email address will remain used by an nonexistent user. For this you can have a Saga that cleans those orphan email addresses.

The cleanest way would be to make this insertion/check when the email verification link is clicked.

  1. After the user is created, you check afterwards for duplicate email addresses with a Saga. If there is only an instance of the Saga then you can be sure that it will detect duplicate email addresses; if there are multiple instances then you will need a collection with an unique index, just as above.

How do I let client now that its request failed?

You cannot send him an email because the email is used be another user. You can push him notifications based on the session ID, as long as he has the same session, or when he logs in the next time (if you have another mean of authentication).

  • Thanks for the link. Greg's pragmatic argument is somewhat funny because it introduces one more point for DoS attack. I could send a ton of queries which will very likely lead to the duplication. – Pavel Voronin Sep 28 '18 at 8:44
  • @PavelVoronin please explain what do you mean – Constantin Galbenu Sep 28 '18 at 9:31
  • I mean that while I generally agree that in normal operation this is a rare event. I can imagine that someone intentionally sends requests for user creation with same email. This will eventually lead to the duplication in the system. If duplication requires manual intervention because it was designed like that, then someone has to spend a lot of its precious time. And in case such inconsistency somehow affects other parts of the system, this may worsen the situation. – Pavel Voronin Sep 28 '18 at 9:44
  • 1
    @PavelVoronin I see, but the DoS attack can be done in any of the application domains, not only on user registration. So, you need to have anti-DoS anyway, most probably as separate module (i.e. something that detects too many requests of some type in a specified interval and blocks it) – Constantin Galbenu Sep 28 '18 at 9:56
  • Well, valid point =) – Pavel Voronin Sep 28 '18 at 9:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.