1 Replies - 356 Views - Last Post: 22 March 2020 - 07:22 AM

#1 Soumikbhat   User is offline

  • D.I.C Head

Reputation: 2
  • View blog
  • Posts: 83
  • Joined: 01-September 13

Design Question - Chat App

Posted 22 March 2020 - 04:31 AM

I am working on a chat mobile app with WhatsApp like functionality. Basic Use case : 1-1 chat system. Users should get message delivery even if they're not logged on to the app but connected to the internet (very similar to WhatsApp).

Design that I am thinking of :
When Client A connects to the server, the server spawns a thread for this UID. This thread will be responsible for handling all communications with A (handling messages that A sends to other clients, as well as delivering messages sent to A by other clients). Similarly, when another client B connects to the server, the server spawns another thread to handle communications for this UID. Thread Id and UID it is serving are stored in an in-memory DB like Redis for faster fetching. I'll maintain threads for users as long as they are online. This includes scenarios when B is not logged in to the app. I'll delete his thread once B is offline, i.e. his internet is off.
If A wants to send a message to B, A makes a server call with his message, his UID and B's UID. The thread handling A's communication hands over the message to the thread handling B's communications (from the DB, it fetches the thread id for B's UID). In case B is offline (which means, this thread is no more present), I'll store this in persistent DB (Mongo), and when B connects to my server, a thread is created for B, which makes a DB call to fetch undelivered messages and delivers them to B.

This is my high level design. Now I want to refine this based on your suggestions and want to clarify some of my queries in this:

1. How should this scenario be handled: When B reconnects to the internet, but does not open my app, he should still get his messages (like in WhatsApp). How to implement this scenario? I am thinking of using FCM (Firebase Cloud Messaging) for Push Messages. But would need some help to identify the event that should trigger this? How will my server know if the client is connected to the internet or not?

2. [noob question alert] In the case, where I have multiple servers behind a Load Balancer, B is connected to a server X and A is connected to server Y. If A wants to send a message to B, A's thread in server Y won't be able to find B's thread. So to solve this, should we also store the IP of the host where the thread for a particular UID is being spawned in Redis? Is there a better approach for this, since this seems to be a very common distributed systems use case?

3. Threads or child processes for UIDs? My thoughts - threads since I feel (please correct me if I am wrong), that the computations aren't much heavyweight, so given the speed advantage of threads over processes, I'd prefer threads.

Is This A Good Question/Topic? 0
  • +

Replies To: Design Question - Chat App

#2 Ornstein   User is offline

  • D.I.C Head

Reputation: 103
  • View blog
  • Posts: 210
  • Joined: 13-May 15

Re: Design Question - Chat App

Posted 22 March 2020 - 07:22 AM

The topic of architecting a scalable chat app is perhaps a bit too broad to cover in a forum thread, but let's start here:

Unless you have a specific implementation in mind and/or know something that I don't, you probably don't want to be spawning threads on-the-fly and almost certainly don't want each individual user to have their own threads.

You'll likely want an event loop and/or a thread pool. Maybe look into how things like Node.js work; I/O completion ports; thread pools in general; the reactor/proactor patterns; etc.

To address your questions:

Quote

1. How should this scenario be handled: When B reconnects to the internet, but does not open my app, he should still get his messages (like in WhatsApp). How to implement this scenario? I am thinking of using FCM (Firebase Cloud Messaging) for Push Messages. But would need some help to identify the event that should trigger this?


As it stands, FCM is pretty much your only option for background push notifications on Android. You can either send push notifications to a user whenever another user sends them a message (in which case the notifications will be sent ASAP, but if multiple messages are sent in quick succession, some push notifications may end up being redundant) - or have some kind of delayed queue system, where push notifications are sent periodically to users who have pending messages (in which case you may reduce redundant notifications, but there may be a longer delay between a message being sent and the end user being notified).

In any case, you wouldn't necessarily want the messages sent in the push notification; you'd likely want your app to fetch messages from the server when a push notification is received and/or when the user opens the app.

Quote

How will my server know if the client is connected to the internet or not?


This is another broad question which depends on a lot of variables (e.g. implementation, what you're ultimately trying to achieve, etc).

If for some reason you want to know whether a user's device has internet access even when the app is closed or the device is in the user's pocket, there are ways (with varying degrees of reliability) to be notified of changes in the device's network state - which you might then use to communicate some information to your server/s (which again may not be reliable).

Quote

2. [noob question alert] In the case, where I have multiple servers behind a Load Balancer, B is connected to a server X and A is connected to server Y. If A wants to send a message to B, A's thread in server Y won't be able to find B's thread. So to solve this, should we also store the IP of the host where the thread for a particular UID is being spawned in Redis? Is there a better approach for this, since this seems to be a very common distributed systems use case?


As mentioned above, these user-specific threads shouldn't exist anyway - and in any case, threads should rarely communicate directly - so much of this question is moot.

Regarding the more general problem of how you share information in a distributed system, maybe look into things like sharding, federation, replication, etc.

Ultimately, you'll likely end up with either one central access point for all information (i.e. one server which either stores all information or is an interface between multiple servers storing information) - or you'll have replicated data across multiple servers.

In any case, in a scenario like that which you described - with a user B connected to a server X and a user A connected to a server Y - there are very few good reasons to have communication between user B and server Y (or between user A and server X). You may instead have communication between servers X and Y - or communication between X (or Y) and some additional server/cluster.

Quote

3. Threads or child processes for UIDs? My thoughts - threads since I feel (please correct me if I am wrong), that the computations aren't much heavyweight, so given the speed advantage of threads over processes, I'd prefer threads.


Again, this thread-UID relationship should ideally never exist in the first place, but generally you would favour threads over child processes in a situation like this.

Hopefully this has given you enough to work with; feel free to ask any followup questions.

This post has been edited by Ornstein: 22 March 2020 - 07:26 AM

Was This Post Helpful? 1
  • +
  • -

Page 1 of 1