Do you even fancy how to design a Facebook like or many other push notifications from scratch without using a third-party API or library i.e. at the core level? Have a read.
A notification
in a message you can display to the user outside of your application's normal UI. When you tell the system to issue a notification, it first appears as an icon in the notification area
. To see the details of the notification, the user opens the notification drawer. Both the notification area and the notification drawer
are system-controlled areas that the user can view at any time. System will also display the notification as a TOAST
when user is logged-in along with increment in the notification drawer.
Lightweight Event Driven Notification System
1.1 Event Generation
The event generation phase happens while processing the response to a user request. As such, we wanted to ensure that there was little or no impact on the response times from where notification is called/generated. To ensure this was the case, all we will do is store the minimum amount of data possible/lightweight message on the queue. We store the minimum amount of data possible or a lightweight object, just a few identifiers, so it shall not slow down the response just to kick off a push notification. Everything after this initial message drop on the queue action is processed out by another consumer which shall produce no impact on site performance.
All calls to the notification shall drop quickly drop a message on the queue.
1.2 Event Targeting
This is the event targeting phase which will receive event from the queue. We may or may not have more than one worker reading from the queue. When a worker receives an event, it loads up any additional information necessary (additional processing) to act on the notification. E.g. for checking to see what users should be notified, whether those users have devices that are registered to receive notifications or if they’ve opted out of notifications of this type etc.
1.3 Message Delivery
The web has been largely built around the so-called request/response paradigm of HTTP. A client loads up a web page and then nothing happens until the user clicks onto the next page. AJAX started to make the web feel more dynamic. Still, all HTTP communication was steered by the client, which required user interaction or periodic polling to load new data from the server. All of these work-arounds share one problem: They carry the overhead of HTTP and also numerous unnecessary HTTP connections when there isn’t actually any update available with the server. Because of this we decided to use NODE JS along with Web Sockets. Node JS will receive the event from queue when it’s published. The WebSocket connection is a persistent connection between the client and the server and both parties can start sending data at any time. The Web Socket connection here will be established at the user login. Based on to whom message belongs and logged in user, the connected Web Socket will deliver the notification on the UI. Shall be only one dedicated Web Socket connection per browser. Single web socket connection can be used not only just dropping notifications but performing other tasks too based on events. This phase will take care of persistence too.
Scalability and Availability
- Ques 1. : How do we ensure that the delivery to MQs are both scalable and highly available?
- Ques 2. : What if the Node JS Worker crashes?
- The first step to ensuring a service is scalable is to divide the workload.
- Workload is divided across two queues configured in ActiveMQ. Already having specialization in managing/configuring ActiveMQ which is a very powerful message broker with advanced features for enhanced availability, scalability, performance and reliability. To provide more scalability on ActiveMQ Brokers, we can allow many brokers to be connected into a network.
- Java Queue Consumer: Spring DMLC took its inspiration from MDBs, it did not replicate these disadvantages; quite the opposite, in fact. The Spring DMLC is commonly used to create what have become known as Message-Driven POJOs (MDP). MDPs offer all of the same functionality as MDBs but without the disadvantages listed above. The Spring DMLC provides many features including Caching JMS resources, dynamically grow and shrink consumers, re-establishes connection on non-availability of broker etc.
- Node Consumer: ActiveMQ is written in Java and has a full-fledged JMS client, but its STOMP support and RESTful API let us interface with the messaging queue quite nicely using Node.js. Node.js is single threaded and currently we would go with only one Node JS Worker and if required can divide the workload across individual Node.js processes anyway, so this can work out well. Configuring our Node.js processes in this way makes it easy to scale horizontally. Whenever we need to add more processing power to the cluster, we can just add more servers. If only one and individual Node JS instance is down, message would still be persisting with the broker.
With Node, you’ll find that STOMP is a great choice of protocol for subscribing to queues. Using node-stomp as a STOMP CLIENT as a way of connecting to queues
- a) Ability to support different STOMP protocol versions.
- b) ACK and NACK support
- Web Socket: The WebSocket API enables web applications to handle bidirectional communications with server-side process in a straightforward way. Socket-io certainly makes working with Websockets very easy. It abstracts many transports, including AJAX long-polling and WebSockets, into a single API. It allows developers to send and receive data without worrying about cross-browser compatibility. Socket.IO provides both server-side and client-side components with similar APIs. Limiting to the user, we would be using Web Socket for now only send data from the server so it would be Unidirectional.
- UI: Socket-io client and JQuery.
Notification Persistence, Quick & Guaranteed Delivery
All notifications will ultimately make to a persistence store. User shall be shown same Notifications in the notification drawer irrespective of the device usage. Persistence shall also allow to keep track of the notifications delivered or not delivered to the user and mark appropriately. This shall provide support to deliver the pending notifications to the user when he is not available or logged-in to the next time when he logs in.
The choice is MongoDB.
MongoDB being a No-SQL database works with documents and collections.
*The persistence shall have minimal or no impact on the notification ‘time to reach’ to the user. *
1.1 Being Quick
- Notifications are usually a highly read object, so we want to be able to get the list of currently unread notifications very quickly, not try and calculate on the fly.
- Being Event-Driven, notifications (intended/subscribed) are delivered to users available in real-time as soon as event is generated (prior persisting).
- The event targeting phase needs to make sure to drop a lightweight notification object on the queue along with list of intended recipient users.
1.2 Guaranteed Delivery
For guaranteed delivery of the notifications when user is not logged-in or auto logged-off by the system and for making notifications available all the time irrespective of the user device. System will persist and will make available the notifications next time user logs in.
Top comments (0)