sending thousands of firebase push notifications with dynamic message - node.js

I've this case when I have to send message to collection of devices using their tokens but I want to put user name or some data that related to the user (variable) in the body of the notification like
Dear %name% you got degree %degree%
The problem now that I've to send a notification request to each user that's mean if I have 100k user => 100k request
Now I'm using Redis queue for the sending but I want to know if there is better way to do that

Not sure how it is used together with Redis, but at last look into it:
Make sure that you send your messages in batches. Build lists of 500 individual messages and send those using e.g. sendAll() from the FCM admin SDK.
Stating the obvious: 100k messages will be 200 requests.
https://firebase.google.com/docs/cloud-messaging/send-message#send-a-batch-of-messages

Related

Excluding consumer of a topic by sender in Pulsar

Intro
We're developing a system to support multiple real-time messages (chat) and updates (activity notifications).
That is, user A can receive via Web Socket messages for :
receiving new chat messages
receiving updates for some activity, for example if someone like their photo.
and more.
We use one single WebSocket connection to send all these different messages to the client.
However, we also support multiple applications/clients to be open by the user at the same time.
(i.e - user A connect on their web browser, and also from their mobile app, at the same time).
Architecture
We have a "Hub" that stores a map of UserId to a list of active websocket sessions.
(user:123 -> listOf(session#1, session#2))
Each client, once websocket connection is established, has its own Consumer which subscribes to a pulsar topic "userId" (e.g - user:123 topic).
If user A connected on both mobile and web, each client has its own Consumer to topic user:A.
When user A sends a new message from session #1 to user B, the flow is :
user makes a REST POST request to send a message.
service stores a new message to DB.
service sends a Pulsar message to topic user:B and user:A.
return 200 status code + created Message response.
Problem
If user A has two sessions open (two clients/websockets), and they send a message from session #1, how can we make sure only session #2 gets the message ?
Since user A has already received the 200 response with the created message in session #1, there's no need to send the message to him again by sending a message to his Consumer.
I'm not sure if it's a Pulsar configuration, or perhaps our architecture is wrong.
how can we make sure only session #2 gets the message ?
I'm going to address this at the app level.
Prepend a unique nonce (e.g. a guid) to each message sent.
Maintain a short list of recently sent nonces,
aging them out so we never have more than, say, half a dozen.
Upon receiving a message,
check to see if we sent it.
That is, check to see if its nonce is in the list.
If so, silently discard it.
Equivalently, name each connection.
You could roll a guid just once when a new websocket is opened.
Or you could incorporate some of the websocket's addressing
bits into the name.
Prepend the connection name to each outbound message.
Discard any received message which has "sender" of "self".
With this de-dup'ing approach
there's still some wasted network bandwidth.
We can quibble about it if you wish.
When the K-th websocket is created,
we could create K topics,
each excluding a different endpoint.
Sounds like more work than it's worth!

Correct way to build an in-app notification service?

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.

Need recommendation regarding rabbitmq

I am creating an chat application where I have a rest API and a socket.io server, What I want to do is the user will send messages to rest API, The api will persist those messages in database and then send these messages to the rabbimq queue then rabbitmq will send these messages to socket.io if the receiving user is online, Else the message will be stored in the queue and when the user will come online the user will retrieve these messages from the queue however I want to implement this in a way like whatsapp, The messages will be for a particular user and the user will only receive those messages which are meant for them i.e I don't want to broadcast messages I want only particular user to receive those messages
Chat should be a near-real-time application, there are multiple ways of modeling such a thing. First of all, you can use HTTP pooling, HTTP long pooling but some time ago there where introduced the new application-level protocol - web socket. It would be good for you, along with Stomp messages. Here you can check a brief example. And sending messages to specific users is also supported out-of-the-box example
1
To send messages to specific sockets you can use rooms: io.to(room).emit(msg). Every socket is a part of a room with the same name as the socket id.
2
I wouldn't wait for the message to be written to the database before sending it out through socket.io, your API can do both at once. When a user connects they can retrieve their messages from the database then listen for new ones on their socket.

Nodejs Email Sending using sendgrid web api

I am developing an email sending service, probably for sending bulk emails using sendgrid web API, but I am not able to figure out best practice for scalable system. I wish to keep a record of all those emails which failed to deliver and retry sending to those failed emails after all emails have been sent. I am using NodeJs, so just wanted to know if there is any way to speed up my process(something like sending multiple emails at the same time)
There are multiple ways to handle this, I will suggest two which seems obvious to me.
(Recommended - Easy) Use Async module's control flow option called queue Async Documentation. You can feed in all the request in form of an array of object request and then change concurrency setting to let's say 100, it'll run concurrent 100 workers at one time and to log errors make a separate mechanism and once all the values have been run through handle it separately.
Spawn multiple workers using node.js native approach.
Sendgrid offers an npm package for node.js integration, so you don't have to reinvent the wheel. It accepts messages at a high rate, so you shouldn't have problems delivering yours to sendgrid. You just dump your messages into sendgrid.
Email, being a store-and-forward system, is inherently asynchronous. That means it operates far from real time. Some messages are delivered in a few seconds, and others take hours (when they get soft--"retry later"--rejections from destination servers, for example).
Sendgrid handles this issue with a "bounces" API. (And with "bounces" features in their web back end application). Many bounces are "hard" bounces, meaning you must avoid trying to send messages to that address again. You can use the bounces API to retrieve a list of bounced messages. You should remove those addresses from your email list, and not try to send them again. (Sendgrid bans users who repeatedly send mailings with a high undeliverable rate.)
They also have an "invalid emails" API. This works like "bounces" and returns lists of addresses that are ill-formed or, if sendgrid can tell, not present on the destination server. Again, you should remove these addresses from your email list. If they're invalid now, they will be invalid tomorrow.
Sendgrid offers all sorts of tutorials on this subject.

Push notification to millions of device + Apns + node.js

My application stack is ios(front-end) and node.js(back-end). I have to send notification to devices. In my node.js part im using apns module to send notification, its working fine......
Now i have to send Mass notification like at a time consider i have 10,000 devices to notified, the logic what im following is
I'm looping through 10,000 devices and calling apns provider.
1.Why this for loop approach
I have to store each notification details in my mongodb collection, so i followed this approach.
The problem is the notification is received by some devices and that too very late(next day).
I read the link also
https://www.raywenderlich.com/156966/push-notifications-tutorial-getting-started
saying apns will reject.
Is the above approach is correct also any way to make all notification deliverer.
Please share your ideas. Thanks in advance.
If you need to process each individual notification before/after it is sent I would instead recommend a design change from a loop and have you look at job queue instead.
With this design pattern, instead of your only step being to loop over notifications and send via APN, you push these notification into a queue/messaging system and have workers which pull from the queue and process (send via APN and write to mongo) the notifications. The nice part of this design is that as your application grows you can add on more workers to handle the increased load without rewriting your application/architecture. Once you have it built it may look something like this:
I personally use RabbitMQ for my job queue, but that decision is something you need to research on your own. For example if you don't want to manage the messaging system you could look into something like AWS Simple Queue Service.
I think looping through 10,000 devices ids and calling APNS provider is not the right way forward. The documentations strictly says here node-apn readme file to reuse apn.Provider rather than recreate it every time to achieve the best possible performance.
If you send notification using arrays of device ids rather than just a device id then you will get a response from the APNS mentioning all the details for each device.

Resources