2

I'm currently building my first ever microservice using NodeJS, but I stumbled upon a problem.

TL;DR ~ How to ensure data consistency between 2 microservices while both having write permissions

Setup

I currently have 2 independent microservices: session & recovery

  • Session: Handles authentication (sign up, sign in, sign out, current user)
  • Recovery: Handles password resets (request a reset, reset the password)

Both services contain an identical copy of the user table. Every record has a version field to ensure data consistency.

I'm using a message broker (NATS) in between the 2 services.

Example

A brief example of how the application flow works.

Let's say we want to do a password reset: Recovery Service:

  1. Request password reset
  2. Generate token
  3. Specify new password (legitimized by token)
  4. Increase the version of the user
  5. Send UserUpdatedEvent

Session service

  1. Receives event with data (user id, user version, new password)
  2. Search for a user with specified id and version - 1
  3. Found? Update the password
  4. Increase version number

Important:

  • The recovery service doesn't hold all the user data. In fact, it's only used to check if the user exists.
  • The password is not stored inside the recovery service, it's send to the session service via the UserUpdatedEvent.

These are the 2 tables inside the recovery service:

  1. Recovery table: Contains the user reference , a generated token, the status (pending, expired, completed)
  2. User table: Contains the user id and the user its version

This works fine, but what if you update the same user simultaneously in both services?

The Problem

What if 2 microservices, that hold a copy of the same table, both modify different a property at the same time?

Example:

  1. Recovery service handles password modification for a user
  2. Session service handles all other modifications for a user (first name, last name,...)

They will both, at the same time, modify their tables. Therefor increase the version count and then emit an event to the other services. When the UserUpdateEvent is received by the other services it won't be recognized as a 'legit' event since there is a version mismatch between session & recovery.

  • Does this mean I should have kept this functionality in one service?
  • Perhaps only one service should be able to modify a table?
  • Maybe I shouldn't keep a version inside the recovery table at all?

Hopefully a more experienced person can help me out!

New contributor
Michiel is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
2
  • First of all, I fail to see why the recovery service needs a user version. Just send a password update to the session service and be done.
  • Even if you use a version with the password update: which would be effect of a collision? The session service should check that the version is the current version, and either accept or reject the change. This implies, that the responsibility of maintaining the version should be only in the session service, not in the recovery service.
  • Can this legally happen? I find it hard to imagine a situation where a user is legitimately logged in to your application, edits his profile, and at the same time requests a password reset. Don't waste 10s of thousands of development cost for a problem that will never occur.
| improve this answer | |
  • thanks for your quick response, totally agree with what you're saying! – Michiel Jul 30 at 12:39
  • so in general this means only 1 service should be able to update the version? – Michiel Jul 30 at 12:43
  • 1
    I always have a problem with "in general" as every solution should be specific to the problem at hand. But yes, in this case, I'd recommend that only the session service maintains the version. If you want a consistency check, have the message include the current version which is known to the recovery service, and - after updating the version in the session - broadcast a message with the new user+version. – mtj Jul 30 at 12:56
3

It seems to me that you might draw the borders of your Microservices based on the wrong criteria. In your case it looks to me you created two services based on different database tables (or at least it seems to be one of the factors that influenced your decision).

I would have all authentication responsibility - which also includes password reset/recovery - in one authentication service rather than having two separate services.

If one service (A) has a too strong dependency on another service's (B) features or data it can often be a sign that either some features or data should be moved into service (A) or the services should be merged into one.

In your case merging the services into one will save you from a lot of headaches, for instance, concerning data consistency.

So back to your first question:

Does this mean I should have kept this functionality in one service?

My short answer is: Yes.

| improve this answer | |
New contributor
afh is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
  • Thanks for your insights! While writing this question I suspected that I was doing something wrong :) – Michiel 2 days ago

Your Answer

Michiel is a new contributor. Be nice, and check out our Code of Conduct.

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.