Ok, so this is a problem, it's been there since the beginning, and it's a difficult one to solve.
10,000 feet view
At the moment, when a plug-in is triggered, it's like a web client sending an HTTP request to a web server. It sends a request and awaits an answer, but before an answer is completed the server dies.
From the client's perspective, it cannot know that the server has died. All it know is that it hasn't gotten a reply in the expected amount of time.
The trick here is, what is a reasonable amount of time to wait before assuming that the server died? Remember, the server cannot say "I have died". It can only reply to the request, or say nothing at all.
We could do what you said, to send a signal (another request) from server (e.g. Maya, or pyblish-standalone) to the client (pyblish-qml) saying "I'm going to close now, you can stop waiting for whatever you expect me to finish".
The problem is that we can't be sure that such a signal would ever be emitted, because things often does not close the way they are supposed to. For example, if Maya is shut down, it could call the corresponding callbacks that may emit this signal. But if it crashes, that won't happen and we're back to where we started.
You're probably already noticed a similar pattern in a web browser. As in, even when internet suddenly goes down, it appears as though the page is still loading, albeit slower. That's because, as a client of the server running somewhere on the internet, it cannot know that the server is no longer there. (As a side-note, Chrome and others do communicate with the OS on some level so as to be notified about breaking network connections, and it can from there deduct that a page might not load and tell you about it).
One way to solve it, might be to have the server emit heartbeats to the client, saying "I'm here. I'm here. I'm here. etc.". So that even though a plug-in runs for many seconds without returning, there is another signal there keeping pyblish-qml notified about that it is still there doing what it's supposed to.
We could then, separated from processing, expect a certain heartbeat to arrive within a certain amount of time, say +-0.1 seconds. If a heartbeat is late, we can assume the server has died and we can cancel whatever was going on.
If we're processing when this happens, we'll need some way of canceling what's going on. Now, we can't kill a running thread. Threads don't work that way. We can kill a process, but not a thread. So on-top of the heartbeat approach above, we'll also need to rearrange our call strategy.
Solution B - Part II
At the moment, requests from pyblish-qml to a host, such as pyblish-standalone, are made via what's known as "long polling". It's making one request, and wait for a reply. Like any synchronous function call that might also take time.
The benefit here is that it's dead simple and doesn't require any smarts about it. We just make a request like we would a function, and as soon as the request finishes, it'll be sent back and handled. Done.
As we can't do that here, we can instead rely on another mechanism which you may be familiar with.
- Make a request to get called back when it's your turn
- Get called back and start the conversation
This is what some banks do when there's 20 people in line and the expected waiting time is 60 minutes+. Rather than you hanging onto the phone without estimate on how long it'll take, they'll call you.
In Python speak, this means making a request but not waiting for it to finish. Instead, we'll give them our number (in this case our port number) and ask them to start running a plug-in. When the plug-in finishes, we call back with the
Technically, this would require both pyblish-standalone and pyblish-qml to be client and server simultaneously, because a server cannot contact a client; it only works the other way around. Luckily, this already happens. pyblish-qml can tell a host to process, we already know that. And we also know a host can tell the GUI to show.
So the foundation is already there. All it needs is someone to either implement the above, or to think of an alternative solution.