We have a React Native app, and we use phoenix channels to send real time data to it. The problem is that data doesn’t come in when the app is in the background. What is the best way to deal with this?
For example, if we were doing chat, and people were messaging back and forth, all works well when the apps are in the foreground, but if a user goes to another app for a minute and then comes back to our app, he wouldn’t have received the messages that were sent while away. What’s the best strategy to ensure he does get caught up on all messages?
Which “app” is in the background?
But from your description I do imply that you talk about the browser tab running the Client is in the background/inactive.
Phoenix does neither care for, nor does it know about that fact if a tab is in fore- or background. It just sends data over the transfer medium until disconnect happens.
If your client misses messages while in background, there seems to be some “optimisation” in your client or the webbrowser that simply does not run callbacks/ignores incomming messages to save CPU cycles.
React Native app. First line of the question.
Also, please keep in mind that the word “app” has a well defined meaning in the BEAM world. Therefore, if you are not refering to an OTP-application you should always make this more than clear.
That’s usually done via push notifications.
No offence but your responses wete not at all helpful.
You can’t read English. The question was clear unless you’re unaware of
what React Native is.
This question is very relevant to the Elixir forums and phoenix npm package
that is the client side for phoenix channels.
I’m not asking about notifying the user when he has switched apps. I’m
talking about catching him up when he puts his app to foreground again.
Is there a simple way to catch him up on the chat or do I have to ask the
server for all the data that’s been missed on reconnect?
When we were using meteor it would automatically update the client with all
the messages that were missed and was wondering if phoenix had something
No offense taken, I know that my english is far from beeing native, my elixir is far better But of course I did understand that you have an React Native “application” and an phoenix “application” and that “the” application did not receive messages when in background. Since you are having two applications but using definite article, its hard to know which app you are meaning.
But yes, I was not aware what “react native” is in particular. I did only know about “React” which is a SPA, written in JS and made the assumption that “React Native” is just a stripped down version of it.
Since I do know now, that it seems to be a React specialised on building cross platform software especially for mobile devices, I can tell you, that you need to learn about the hosts application lifecycle and how it maps to RNs application lifecycle.
Unless you get your Operating system to actually spend CPU cycles and network (and thus battery life and money) to your application while it is in background and therefore not needed by the user, you will need to ask the server for missed messages in the meantime.
The same applies when you write a real native application for that operating system.
Following that argument your problem can be solved by a windows or linux community as well, since your phoenix application is able to run on both operating systems.
you can receive data in the background via push notifications. however this can be complex. but depends on your persistence strategy. (eg this is what whatsapp does)
if you have the messages on the server the easiest is to do it in the ‘resume’ event https://facebook.github.io/react-native/docs/appstate.html
but it all depends on the chat and the nature of it etc.
you can also do it in an ‘after_join’ in the phoenix channel (like you usually do with Presence).
I would also consider doing a disconnect on ‘pause’ and then a ‘connect’ on resume… (especially on android afaik it will keep the ws connection up in the background, and drain the battery) - in that connect you could then pass a timestamp or id of last received message etc.
many ways to do it…
I’m not asking about notifying the user when he has switched apps.
And I’m not suggesting it …
What I do suggest are “in background” notifications (not shown to the user), which (when received) make the app perform certain actions (predefined by you), like save the unread messages.
And yes, you would have to request all the missed messages explicitly if you don’t want to use push notifications.
Phoenix channels do not guarantee that the client will ever receive a message, they only guarantee that it will be sent. This is consistent to how messaging in the beam ecosystem works in general and therefore something which feels natural for most of us m
Phoenix channels’ default transport is ws (tcp), so I wouldn’t say that there is no guarantee … Same for the messages within an “erlang cluster” (in case you are talking about distribution).
That’s only default. Fallback is long polling. Also even tcp does not guarantee that a message will be received, only that you will be made aware of the fact if it has been received or not
Forum etiquette demands that we give people the benefit of the doubt. Avoid condescending remarks and, most particularly, direct insults.
For React Native I’m guessing you are running it on a phone/tablet/tv/etc… When one of those applications are backgrounded then they are frozen.
In this case you will do one of two things from your Elixir/Phoenix server:
- Either hold all the state for them and send it all at once when they reconnect, they they will get all the data they missed when they come back.
- Either send the messages over a Push notification service to the backgrounded app, this means they will get all the data in real-time, even when the app is backgrounded, however this method costs you money. ^.^;
Push notification service […] costs you money. ^.^;
Really? I think it was free (at least apns).
I think I’ve misunderstood you. You probably meant a third-party service. But it’s not that difficult to make it work with elixir/erlang. There are quite a few working libraries for that.
Third party services yeah. You ‘can’ do it yourself but be careful, a lot of phone providers and some phone OS’s will not prioritize your messages and they can still vanish because they are irritating… >.<
I can only talk about ios, but I’ve done it a few times for ios, it wasn’t that difficult. And I think it worked fine.
Since the OP never shared how they solved the problem, I’m gonna take the liberty to give a theoretical suggestion:
Do as Dropbox does: every client keeps a last transaction ID and when the client reconnects, then send the events they haven’t received yet, in order (Dropbox also reduces those events by having some cancel each other out; imagine if you uploaded 20 files and deleted them minutes later, and your client on another laptop gets powered on the next day – these 20 files will never be downloaded because they are also already deleted).
I am afraid the burden of keeping events that your user’s client devices aren’t caught up to yet lies with you.
That does however give you the opportunity to delete all events which are already synced with all the user’s devices… So it’s not a huge overhead, unless someone turns off one of their smartphones and doesn’t power it up for 5 years. (But you can handle that as well; you can keep events for X months and then when a client that hasn’t connected in a long time eventually connects, simply force them to resync from scratch or better yet, send them the full state afresh.)
So in short, an append-only event database (combined with keeping pointers to events per user device) looks like the best fit for your scenario.
If your usecase is chat messages then use fcm (for Android) and apns (for iOS) to wake up the client. Do not use it to send the chat message. After wake up the client should reconnect in the background and fetch the pending messages.
For iOS one has to know that if your iOS app is not VoIP enabled then it won’t wake up if the user force closed it (double home button tap and swipe up on the app).