Design – a good practice to push notifications in a “near real-time” delay in this case

Architecturedesigndomain-driven-designreal timeredis

I want to enable some real-time notifications about friend's activities (social network).
Technical context is: Webapp calling backend (REST API's).

Scenario is:

Kevin follows Bob.
When Bob posts a new comment, Kevin should be notified immediately (near real-time).
Besides, when Kevin logs in, he should be able to see some past notifications, similar to what Facebook does.
Meaning that notifications should be stored somewhere.

Here's the technical workflow:

  1. Bob posting a new comment involves an insert in database of this new comment.
  2. As following Domain-Driven-Design, the event CommentedItemEvent is triggered.
  3. A distinct worker in the same bounded context (long-running process, polling the database each second) listening to this event captures it.

At the end of 3, I see 2 possibilities:

  • Creating the corresponding notification, storing it in database and THEN sending it to Redis Pub/sub. This one would feed some specific subscribers acting on the WebSocket connection to send the notification to Kevin's client.
  • Creating the corresponding notification, then sending it to Redis THEN storing them in database.

Regarding the first possibility, the advantage would be the transactional aspect. Indeed, no noticification could be sent if it wasn't saved before. => Integrity.
However, the drawback is that the database insertion could slow down the process of "near real-time notification".

Regarding the second possibility, notifications are immediately sent but if some failure happens regarding database insertion, Kevin might have wondered:

"Humm… I received the Bob's notification, I'm sure I saw it. So why a simple page refresh doesn't show it anymore?" => Indeed, it wasn't persist successfully, so can't query it.

What is a good practice regarding this use case?

Of course, one faster way would be to not involve an event listener for this case, but it would violate some principles regarding Domain-Driven Design. IMHO, listener polling database in its own bounded context is necessary. (evoked by Vaughn Vernon in this book IDDD – "Building an event store")

Best Answer

Event handling is not necessarily something internal only to the Domain instance. Sometimes, an external service handles more appropriately such events needs than an internal implementation.

Text Messaging for instance, can be handled better by an XMPP or IRC services, which are interfaced as dependencies into the domain, through an common interface (i.e. notify(message) looks the same to the sender within the domain).

So you may have few domains: one for the Message Logic, another for Message Persistence and another for Message Sharing.

A specialised external service could accept connections from Message Sharing instances, which handles cases and events, putting them through Message Logic specifications and rules.

Message Persistence can connect to the same service, and just handle the storage of the messages in an appropriate database, and even update some search engine.

All related, yet uncoupled, domains. For sure, you will need to work more on the guarantees of each domain (like CAP theorem and latency).

Related Topic