-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
restarting jxcore-cordova #133
Comments
@mohlsen We had used jxcore multi tasking for that purpose on our app for App store. Once JS land receives an event that the app is going background, we pull the plug of task and everything with it. The right approach here can be that JXcore is giving an option to free all the open sockets / ports per request. We wanted to implement that while ago but couldn't prioritize yet. |
ok. we'll take a look at https://github.com/jxcore/wifi-shoplist-app to see if that will work around it for us. thanks |
I was talking with @obastemur and I thought I would clarify what is going on. The issue is that when an iOS app is moved to suspended mode the OS apparently kills all the app's ports in a fairly odd way. Rather than just closing the ports it leaves them in a ghost state where they appear to the app to be open but in fact are not. So, for example, imagine that you have a server listening on port X. The app goes into suspended state and port X's connection is killed by the OS. But the app isn't told about this since it apparently happens after the app was suspended. In our case when the app comes back and runs JXcore the server we had listening on port X thinks its still listening on port X since it was never notified otherwise. In the simplest case we could just call close on the server and then try to grab port X again. But there are at least two serious problems here. The first problem is that another app could have grabbed port X in the meantime. There is a background state in iOS where apps can apparently keep ports for some time before they are suspended. So the point is that we can never rely on hard coded ports. The second problem is more dire, it turns out that LibUV really doesn't like this situation and in practice this means that at best we might never be able to recover the memory associated with the ports that were active when the app was suspended and at worst the whole app can crash. For apps like wifi-shoplist that only work in the foreground the solution is that as soon the pause event fires just close down everything. You can see wifi-shoplist initiate this behavior here. Things get more complicated though for apps that want to run in the background. At a minimum apps that run on Android and iOS need to understand the system's very different behavior and not go killing everything when Android goes into the background. In iOS in theory one could ignore the pause event and instead write native code to try and register the methods discussed here and use that to keep the app alive for awhile. The trick though is to make sure that one pays attention to the last warnings and closes down everything and cleans up in time. This is critical because as explained here there is no warning before going into suspended state and at that point it's too late to prevent memory leaks/crashes. |
So, there are no any chances to notify app about soon killing by the OS? I use background plugin and watch for free mem periodically, and when it goes under my soft limit I use that plugin to force the app to go foreground. This helps to save app and its sockets for hours! But it would be more easy, if there would be any more determined notify from OS.. (My app is for Android) |
For whatever it's worth we are planning on using the standard onPause notification to tell us when to clean things up. We then set everything up again onResume. Keep in mind that iOS really doesn't have anything like Android's background or service mode. Once your app is out of foreground it's mostly dead (there are some exceptions but they are convoluted). |
@Zeipt this is iOS only. As for GC, you might use jxcore.tasks and unload thread instead of killing the process. |
@yaronyg yes, I know abt iOS limits, so I just understood that there cant be anything really secure and private on this OS, So I just decided to not make my app available for iOS. |
@Zeipt you may try BTW; (ping / close / recreate ) approach below works for iOS. So @yaronyg you may not have to force kill the sockets etc. as soon as you receive
I believe this can be automated internally for all the sockets without adding extra request etc. layer. |
@obastemur now I'm confused. I thought you said that if we didn't fully close the server socket before we were put to sleep then when we woke up we would, at best, lose memory and at worst crash the app. The code above doesn't have any knowledge that we are going into the background and wouldn't close the sockets before we did. Also I thought there was a race condition where, while we are in the background, someone else could grab port 3000 and when we come back that app might itself still be in background but not suspended state and so we wouldn't be able to get the port ourselves? |
I'm still behind that with a small difference. Sample I've shared doesn't leave any client socket behind (it calls end) As for the race condition, there is no such a thing for iOS. Once the other app is on background (so your app can be on foreground) you can reallocate and use the port (as the sample does) It's indeed different comparing to what we have talked over skype but as for iOS 9.2, above sample works without any issue. |
@obastemur great! Thanx! It works! |
Sorry for being thicker than usual but this is really important and will cause changes to our plans so I want to make sure I'm following along correctly. Question 1 - Race Condition Will App B's attempt to grab port 3000 work? Assuming it does work then time 3 - App B goes into the background but is not suspended, so it is still listening on port 3000 Question 2 - Memory leaks and crashes Time 0 - App A grabs port 3000 and has incoming connections to it I take it the existing connections will be dead and the port will be lost. But you are now saying that there won't be a memory leak or crash? We just need to realize we came out of background and restart the server? The difference from before being that we can now do this after we come back from suspended rather than before? |
Yes.
I guess this may happen on any OS for any networking app?
When there are active connections, the behavior is undefined. So we might expect everything. The scenario I'd shared above was based on no open
As I tried to explain, this all depends to the connections left open. |
O.k. so it sounds like if I have a server that is listening on a port and if that server has no active incoming connections then it's o.k. to leave it listening while it is suspended and that no memory will be lost and no crashes will ensue. Instead we just have to close the server when we come back into the foreground and restart it? |
Much better than dumping the whole thread. |
Ahh and now we get to the crux of my confusion. I never thought we were supposed to dump the whole thread. I thought we only needed to close down all the servers before we went into suspend on iOS. I didn't want to dump the thread because if I remember correctly each thread requires a full spidermonkey context so we would have one full context for the parent thread (that we aren't using) and then another full context for the child thread (that we are using). Although I still suspect that every once in awhile we will need to drop all of JXcore and restart it en mass so we can clean up everything. But we'll have to handle that at the native layer. |
Do to issues where iOS pulls ports when apps are placed into the background, it would be a desirable feature to be able to restart the jxcore process when it is running under cordova. We are having problems resuming network requests (outbound from jxcore) after the app resumes.
If jxcore-cordova could be stopped / started / restarted, it seems like apps using could catch the iOS events indicating that it is entering / leaving the background, and then shutdown jxcore. Alternatively or in addition, when the app is resumed, it could start / restart it.
Is seems like right now from the docs and code, jxcore starts up automatically, and calling
loadmainfile(...)
is the only real way to start your app. Couldloadmainfile(...)
be called again to restart the app?We using Thali in our app, they have an issue to investigate this (thaliproject/Thali_CordovaPlugin#408), but our app also makes network requests outside of Thali.
The text was updated successfully, but these errors were encountered: