xmppjs / xmpp.js

XMPP for JavaScript
ISC License
2.18k stars 372 forks source link

The xmpp is suspended by ios in background #902

Open opentechiz opened 3 years ago

opentechiz commented 3 years ago

When our application go into background, after a few minutes (it depends on phones), when we goback to the foreground, the xmpp is suspended, and we can not continue to send stanzard.

On Android, we call disconnect method to close the socket and it works. But on iphone, this method does not work.

Do you guys have any ideas about this issue. Thank in advance.

nghuyy commented 3 years ago

My idea: Don't use IOS device :)

sonnyp commented 3 years ago

If I remember correctly:

The problem is that iOS pauses all timeouts/intervals when the application goes to background and never resumes them. The solution is to disable reconnect before the app goes to background and re-enable it when the app goes foreground.

Something like

AppState.addEventListener('change', (appState) => {
  if (appState === 'background' ) }
    client.reconnect.stop();
  } else if (appState === 'foreground') {
    client.reconnect.start();
  }
});

start and stop aren't documented, though, so this might break in a future release. If you fix the issue for yourself, please report back, and we can have a look at how to get this by default.

opentechiz commented 3 years ago

Hi @sonnyp thanks for your help. I try the reconnect.start() and stop() does not work on ios too, when we comeback to fg, the xmpp can not reconnect. For now, we are trying a solution to stop reduce the TCP keepalive on xmpp server, so that the socket will be stopped by timeout.

sonnyp commented 3 years ago

does not work on ios too, when we comeback to fg, the xmpp can not reconnect.

does not work and xmpp can not reconnect is not enough for me to help you. Please share code and precise observations.

The snippet I shared is just an example on top of my head, most likely, you'll have to tweak it. Perhaps consider using the inactive app state. https://reactnative.dev/docs/appstate#app-states

Also xmpp isn't magically gonna reconnect if you disable reconnect. You need to start the connection after resuming. Try something like

AppState.addEventListener('change', (appState) => {
  if (appState === 'background' ) }
    client.stop(); // this might take too long try client.socket.close() as well
    client.reconnect.stop();
  } else if (appState === 'foreground') {
    client.reconnect.start();
    client.start();
  }
});
opentechiz commented 3 years ago

Thanks Sonny. I tried client.stop(), it works fine but the delay is too long. I will try the connection.close in next steps. I checked inactive/background for sure, the reconnect stop/start does not work well. I greatly appreciate your help.

On Wed, Jul 7, 2021 at 4:24 PM Sonny Piers @.***> wrote:

does not work on ios too, when we comeback to fg, the xmpp can not reconnect.

does not work and xmpp can not reconnect is not enough for me to help you. Please share code and precise observations.

The snippet I shared is just an example on top of my head, most likely, you'll have to tweak it. Perhaps consider using the inactive app state. https://reactnative.dev/docs/appstate#app-states

Also xmpp isn't magically gonna reconnect if you disable reconnect. You need to start the connection after resuming. Try something like

AppState.addEventListener('change', (appState) => { if (appState === 'background' ) } client.stop(); // this might take too long try client.connection.close as well client.reconnect.stop(); } else if (appState === 'foreground') { client.reconnect.start(); client.start(); } });

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/xmppjs/xmpp.js/issues/902#issuecomment-875443512, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALE4YD5SXJCIVNSGFNZJKETTWQMM7ANCNFSM474UIXOQ .

samueldominguez commented 2 years ago

@opentechiz did you find a workaround for the delay?

opentechiz commented 1 year ago

@samueldominguez the delay of stop and start again depends on the xmpp server too (how it authenticates the users, ..).

otech47 commented 1 year ago

I am seeing some of this problem as well in my React Native app

After configuring the client and calling xmppClient.start() I store the reference to xmppClient in React Context, but sometimes I would find messages get sent out and lost with no response from the server, especially when coming back from background app state. Seems there are no error or disconnect events emitted by xmpp either in these rare cases...

My first approach was detecting background/inactive => active AppState and then trying to send presence to server to see if an ack stanza is received, but if 5 seconds pass with no ack, I call xmppClient.restart()

This did not seem to resolve the issue and it keeps happening occasionally. Sometimes coming back to foreground works fine with no extra logic needed so this bug is very hard to reproduce

My best guess is that since this library does not use NativeEventEmitter that taps into native code and instead uses the npm events package, maybe there is something about JS memory management that is disrupting the client's ability to reconnect and resume the stream. OS-level garbage collection may be taking over at a certain point and since this library was not originally built for mobile use, maybe there is more robust support needed here... Perhaps the use of react-native-events would help?

Now I am tweaking my xmppClient.send(xml('presence')) solution and after my 5sec timeout of no ack from server, I am instead just calling xmppClient.stop() and xmppClient.reconnect.stop() and then totally rebuilding a new xmppClient from scratch and storing it again in React Context.

I am hoping this works and doesn't cause memory leaks but would like to ask @sonnyp if there is a stronger way of making sure the old xmppClient is totally destroyed from memory before rebuilding a new client?

will see how this goes...

Screenshot 2023-03-07 at 2 24 35 PM

timothyerwin commented 1 year ago

will see how this goes...

@otech47 any updates? I'm interested in using this in a react native app...also for the chat display do you handle all that yourself or is there some react native library that does the heavy lifting?