As I am moving a part of the monolith app logic to a microservice, I am standing before a problem with scalability.
Currently, the main monolith runs on different instances, and has some scheduled services. Some of those services are pretty straigthforward, but there are some services that are sending emails basing on a result of a database query. The actual solution bases on optimistic locks, the service on the instance that is sending the email first is saving the last notification time on the database, if another instance tries to send the notification to the same user again, this happens:
try {
final long userId = notificationService.getUserIdToNotify();
if (nonNull(userId)) {
mailService.sendNotification(userId));
}
} catch (ConcurrencyFailureException e) {
LOGGER.debug(
"User has been allready notified by another thread or instance.");
LOGGER.trace("Optimistic lock", e);
}
The NotificationService
returns an UserId
if the user wasn't notified previously, or a null if the user was allready notified.
Doesn't seem to be the best solution, but it somehow works.
I could move the logic to a single microservice, remove the optimistic lock logic, but I have recieved a requirement, which states that the microservice should be prepared for scaling, and therefore I should be aware of those optimistic locks, and design the microservice so the croned services inside it should include logic that will prevent other instances from doing actions more than once (for given period of time when they run).
I am not a microservice expert, but from what I see, there are some design problems rolling at me at dangerous speed.
Should this microservice be scaled? It does some operations on the database on an hourly/daily/weekly basis, and as the logic will be separated from the monolith, it shouldn't affect it... except for performing some operations on the same database which is the monolith using.
And if the service should be scalable, what solution would be best? I was thinking about using Redis to store keys and values of userId and a timestamp, and check those entries before performing actions, to prevent duplicate/unnecessary ones.
I am a little bit stuck now, and something in my lizard brain is saying that there is allready a solution for this, but I just seem to miss it.