I want to implement a notification system like facebook does for an Angular 7 app. I am currently using nodejs ad my backend and socket io for the socket connection.
I understand the principle of sockets, events, observables... however, I can't wrap my head around how should I create a socket for each user to receive notifications.
I thought about creating a channel called 'notifications' and then subscribe all logged in users to that channel. When a user does anything that triggers an event that requires the app to create a notification I will broadcast the notification to all users and only display it if logged in user is inside the receivers array of the new notification object.
HOWEVER I think this is a very bad approach as all users will be listening to this event and only a very small amount of them will display it. It seems like I am wasting a lot of resources with this approach. Is there a proper way to handle this or is my approach the one used by companies like Facebook and Instagram
Related
Background
I have a monolith Node.js + PostgreSQL app that, besides other things, needs to provide real-time in-app notifications to end users.
It is currently implemented in the following way:
there's a db table notifications which has state (pending/sent), userid (id of the notification receiver), isRead (did a user read the notification), type and body - notification data.
once specific resources get created or specific events occur, a various number of users should receive in-app notifications. When a notification is created, it gets persisted to the db and gets sent to the user using WebSockets. Notifications can also get created by a cron job.
when a user receives N number of notifications of the same type, they get collapsed into one single notification. This is done via db trigger by deleting repeated notifications and inserting a new one.
usually it works fine. But when the number of receivers exceeds several thousands, the app lags or other requests get blocked or not all notifications get sent via WebSockets.
Examples of notifications
Article published
A user is awarded with points
A user logged in multiple times but didn't perform some action
One user sends a friend request to another
One user sent a message to another
if a user receives 3+ Article published notifications, they get collapsed into the N articles published notification (N gets updated if new same notifications get received).
What I currently have doesn't seem to work very well. For example, for the Article created event the api endpoint that handles the creation, also handles notifications send-outs (which is maybe not a good approach - it creates ~5-6k notifications and sends them to users via websockets).
Question
How to correctly design such functionality?
Should I stay with a node.js + db approach or add a queuing service? Redis Pub/Sub? RabbitMQ?
We deploy to the k8s cluster, so adding another service is not a problem. More important question - is it really needed in my case?
I would love some general advice or resources to read on this topic.
I've read several articles on messaging/queuing/notifications system design but still don't quite get if this fits my case.
Should the queue store the notifications or should they be in the db? What's the correct way to notify thousands of users in real-time (websockets? SSE?)?
Also, the more I read about queues and message brokers, the more it feels like I'm overcomplicating things and getting more confused.
Consider using the Temporal open source project. It would allow modeling each user lifecycle as a separate program. The Temporal makes the code fully fault tolerant and preserves its full state (including local variables and blocking await calls) across process restarts.
I'm building an application in which we have worked on Payment gateway named flutterwave.
And now the scenario is on every success or failure of a payment, I receive a webhook and then we take further actions such as sending emails, SMS and updating the statuses of the payment in the DB.
For now, we have implemented polling in the client side and for a particular time span if the client receives a status (success or fail) we show it otherwise they can check later it in the payment history page.
Now we want to remove this polling and update users in real time about the success or failure of a payment.
What are the ways by which we can achieve this?
The questions are how we will notify a specific user about the same as we have a multiplatform app and the same user can be logged in different platforms.
What you are looking for is a real-time communication pattern with WebSockets a layer 7 protocol in the OSI model which offers bi-directional communication.
This means that you can establish communication between your servers and your user's browser (client). As a result, you can send notification data to the client and consume and react to the notification, by showing visual cues in your UI for the user to see.
Some examples of implementing WebSockets with Socket.io and Nodejs: https://dev.to/novu/sending-real-time-notifications-with-socketio-in-nodejs-1l5j
There are also paid services that can offer this functionality like Pusher, and I would actually recommend that route at the beginning so you can avoid spending too much time implementing this and focus more on the stuff that matters and is part of your roadmap.
Additionally, you can use Push Notifications as another way to notify your users even when they are not using the app.
I am trying to implement private messaging with socket.io for my mobile applications which have a direct messaging feature like Instagram. Right now, I am using Node.js and React Native. I am kinda new to socket.io. I saw many examples of that. However, one thing is not clear in my mind.
User clicks "send message" button. Then I create a socket connection and the user joins a room with socket id. Then user sends a message to that room.
The problem here is, how other user will get the message? Because at this point, I don't think other user knows the room id. Of course if there is a better solution for that, I am open to every suggestion.
One thing you can do is create a room for each person. When the person logs into your app and connects with socket.io, you'll want to have them automatically join the room with their user id.
Then when someone wants to send them a message, they can just send the message to the room for the receiving user.
However, I think if you are building a messaging app, socket.io is not the right way to go. As far as I know you can't listen on sockets while the app is in the background (and even if you could, it would drain your users' battery life). You should use push notifications instead and use the data field (e.g. zo0r/react-native-push-notification and firebase).
I'm trying to build a realtime (private) chat between users of a video game with 25K+ concurrent connections. We currently run 32 nodes where users can connect through a load balancer. The problem I'm trying to solve is how to route messages to each user?
Currently, we are using socket.io & socket.io-redis, where each websocket joins a room with its user ID, and we emit each message they should receive to that room. The problem with this design is that we are reaching the limits of Redis Pubsub, and Socket.io which doesn't scale well (socket.io emit messages to all nodes which check if the user is connected, this is not viable).
Our current stack is composed of Postgres, Redis & RabbitMQ. I have been thinking about this problem a lot and have come up with 3 different solutions :
Route all messages with RabbitMQ. When a user connects, we create an exchange with type fanout with the user ID and a queue per websocket connection (we have to handle multiple connections per user). When we want to emit to that user, we simply publish to that exchange. The problem with that approach is that we have to create a lot of queues, and I heard that this may not be very efficient.
Create a queue for each node in RabbitMQ. When a user connects, we save the node & socket ID in a Redis Set, so that when we have to send a message to that specific user, we first get the list of nodes, emit to each node queue, which then handle routing to specific client in the app. The problems with that approach is that in the case of a node failure, we may store that a user is connected when this is not the case. To fix that, we would need to expire the users's Redis entry but this is not a perfect fix. Also, if we later want to implement group chat, it would mean we have to send duplicates messages in Rabbit, this is not ideal.
Go all in with Firebase Cloud Messaging. We have a mobile app, and we plan to use it for push notifications when the user isn't connected, but would it be a good fit even if the user is connected?
What do you think is the best fit for our use case? Do you have any other idea?
I found a better solution : create a binding for each user but using only one queue on each node, then we route each messages to each user.
I'm attempting to create an application which will work as a chat app. I'm currently contemplating the best way to do this and I'm thinking of going with a server sent event package such as the following. Every conversation would have an id, and the message would be emitted under the id. For instance
stream.emit(1512, "Hello") would send the message and
stream.on(1512, function(message){console.log(message)}) would print the message. Only the chat members would have the chatId.
I was initially thinking of using websockets but I thought that not every user should be receiving data, as chats were private and I didn't want to configure authentication within websockets.
Back to server sent events:
I have a few questions on the topic.
Are they efficient and, if not, what would be a more efficient solution
Is the method of sending chat through a randomized, hashed, id (such as 309ECC489C12D6EB4CC40F50C902F2B4D) secure?
Would you recommend a different method for sending chat? This is to be implemented as a mobile application where individual users can chat privately with oneanother so, again, security is pretty important.
Thanks.
I recommend the client-call package (disclaimer: I wrote it). It provides a very simple method to run a client-side method from the server code.
Besides this, you can always just put the chat messages to a db collection and remove them after some time.