I’m working with 2019r3.1 and a compiled web service (no UI) on Linux (64-bit). Here’s the code:
If shutdownRequest Then
MessageAdd(CurrentMethodName + ": shutting down in 20 seconds.")
// Breathing room for script completion & possible upload new exe
Xojo.Core.Timer.CallLater(20000, AddressOf QuitApp)
End If
The above is triggered in a timer (main thread) and works fine. Here’s the QuitApp method:
MessageAdd(CurrentMethodName)
App.Quit()
This concept works most of the time, but not when the shutdownRequest is set after what appears to be a hanging thread because of an open HTTP socket.
What happens in that case is the “shutting down in 20 seconds” is being logged infinitely (timer works fine) but the QuitApp method is never logged / called.
Could it be that the hanging thread blocks CallLater somehow? Can I check that or is there a workaround?
The code for the timer is in the first post. When the flag {App.shutdownRequest} has been set, it calls the App.Method.
This always works, except in the scenario I described earlier.
In both cases {timerShutdown} happily keeps on firing every 5 seconds, but the {QuitApp} is not called if there’s a hanging (not properly cleaned up - destructor didn’t run) thread / HTTPSocket (HTTP error?) in another part of the App. Therefore I was wondering if this somehow can mess up CallLater.
As a workaround I’ve added an extra counter in the timer that wil directly call the method after a couple of cycles. It’s not easy to test though as this scenario almost never happens…
Correct. Should that help or even matter? Does that influence CallLater?
My app is a web service which does not get incoming connections other then pages received from outgoing REST calls.
Also, this code works 99% of the time. It’s only a problem after the scenario I described earlier.
It’s not that the main thread(s) are busy since everything has been shut down too. The app has plenty of time, which is also witnessed by the precision of the timer going off. Even with every thread running full blast this mechanism works fine as I have sleeps all over the place…
So does it stop accepting new ones and kill all outstanding REST (HTTPSocket) calls? So all threads waiting for a HTTP reply are going to be disrupted?
If that’s the case I won’t use it until after these threads have been gracefully exited…
If by web service you mean a console app / service application maybe you could use a different approach.
Your main thread will have some kind of loop which keeps the process running.
Rather than your shutdown using CallLater to trigger a method to execute app.Quit, why don’t you use a boolean property which indicates if the loop should continue. Your shutdown detection code would flip the property value which would exit the loop and end the process.
I appreciate the input, but how would this help me? Right now the app works fine and it’s heavily multi-threaded so I don’t see how or why I would have to change this. Not sure it would be a better design to begin with, but I’m open for good arguments!
Oh, it looks like you are doing this using a Desktop project.
Is there any reason why you aren’t using a Console project since your app doesn’t have a GUI?
Can you replicate this in a small project that you can upload here for us to look over? If you need to block a connection fir the test just try to connect to a random port on localhost.
Thanks for the replies guys! Somehow I didn’t get an email from the forum.
@ - A small project… Dunno about that, will take some time as the App is fairly complex with lots of timers starting threads which spin up threads running (e.g.) XojoScripts in other threads. I’m pretty sure that’s related to the issue.
@James Dooley - I already track the threads because I need to know if they’re finished. That gets double checked when the CallLater fires after 20 seconds. If it fires.
For now I’ll settle for extra counter I’ve put in. Also I’m going in to see if I can find a way to catch and destruct the hanging thread (reference?) somehow.
Just for the record: CallLater is not completely clean though. Maybe it gets queued (?) after (blocked by) the hanging thread or something? No clue how this stuff works internally.