Stopping pyblish_qml process on Maya exit

Hi there,

This is on a Windows 7 machine, Maya 2017 64-bit

I’m attempting to integrate Pyblish into my company’s pipeline but have a dilemma with how to handle the external python.exe process that is used for launching the pyblish_qml UI.

The primary constraint I have is that leaving a cmd window open that the artists have to leave upon and manually close is not okay.

The second constraint is that the process has to be non-blocking for Maya during startup as we already have a lot of plugins and startup logic to run.

So, I’ve attempted to launch the process using:
subprocess.Popen('python -m pyblish_qml')

This leaves a cmd window open and also doesn’t close when Maya closes. Adding shell=True makes the cmd window go away, but again, there’s a lingering python.exe process in the background once Maya closes.

I’ve tried keeping track of the process ID and killing it using a Maya callback such as:
OpenMaya.MSceneMessage.addCallback(OpenMaya.MSceneMessage.kMayaExiting, kill_process)

But this didn’t do anything.

I also tried messing around with the multiprocessing package but couldn’t figure out a combination that works.

Is there any way to tell the process to terminate from Maya? Or a way to keep the python.exe process parented to the maya.exe process so it automatically exits when Maya does?

Thank you!

Hi @derrick,

Nesting of processes is something I’ve struggled with myself, but unfortunately that is an OS thing and Windows simply isn’t fit for this task.

Python has an exit handler, atexit, but it isn’t triggered on crashes. You can technically best processes in both Windows and Unix but on Windows at least it doesn’t take children with it when a parent dies.

Have a look at pyblish-tray. It creates a tray icon rather than a console window and e ales triggered hane artist to manage the process from there.

Alternatively have a look at setting up pyblish-qml to launch at startup of Windows as a service. It is safe and expected to let qml run indefinitely and never close.

Another option would also be to look at pyblish-lite, since it seems like you want a GUI process to open/close when needed.

@marcus thanks for the recommendations!

Unfortunately, atexit does not appear to work in the Maya interpreter. See here: http://tech-artists.org/forum/showthread.php?2324-atexit-Python-package-functionality-broken-in-Maya

I didn’t know pyblish-tray was a thing, I’ll check that out today! As long as there’s a way to make sure only one copy of it is running at a time… otherwise it’d be the same problem as I’m having now.

Starting up pyblish-qml might work, but is something I’d like to avoid as my team is very large and we already have a bunch of services and background apps we depend on (build monitors, version control, etc) and I’d like to avoid adding another dependent process. If at all possible, I’d like to keep pyblish limited to the current Maya session but I may have to compromise on this.

@tokejepsen thank you for the suggestion but unfortunately pyblish-lite isn’t an option for my team right now due to this issue I filed on github: https://github.com/pyblish/pyblish-lite/issues/90

We are using pyblish exclusively for its “Validate” step so not being able to reliably flag plugins as optional is a deal breaker.

I won’t pretend to know how/why this is happening, but it appears this is no longer an issue?

What I’m seeing is, after launching the process on Maya startup via:
subprocess.Popen('python -m pyblish_qml', shell=True)

That only one python.exe process is ever running. If I close Maya and restart it, any newly created processes appear to be immediately killed without me having to do it.

I confirmed this by checking the pid’s of the processes. The only one that lingers is the first one to be launched. I can manually kill it but there’s really no need since the goal was to make sure only one was ever running.

Do you guys in fact have some kind of redundant process checking built-in to pyblish-qml? I can’t imagine why the extra processes would die instantly unless process termination is included in the package.

Edit: looks like there’s a check for an existing server in __main__.py, is that correct?

Yes, only one QML process is ever started. Upon starting a new process, a check is made to ensure none else is running.

This is a recent change.

Hi @derrick, just to follow up on this. Did you get it sorted at all?

Hey thanks for following up… I would have to say “no” because I’m seeing various issues pop up from leaving one process going at all times. These are issues that are hard to reproduce, but I think they’re more likely to occur if I leave my machine on for several days at a time or put it to sleep and wake back up, for example.

Sometimes I’ll start Maya and then attempt to show Pyblish QML, and the window does come up but none of the controls respond to mouse input, eg. checkboxes won’t check/uncheck when clicking on them, or the “reset” button does nothing when clicked.

Killing the process via Task Manager and restarting seems to do the trick, but obviously this isn’t a proper solution for a large team.

I’d really love to see a permanent solution to this on your side as right now I can’t really pull the trigger on rolling this out to my company until I can demonstrate more reliable/consistent behavior. If there’s anything I can do to help you guys nail something down, please let me know as this tool will be a huge win for us in our efforts to produce cleaner, validated content.

Thanks for reporting this @derrick, I remember having gotten reports of similar issues in the past. I’m sure it has to do with how communication happens between QML and Maya, they are essentially two web servers passing messages through sockets and bind their own ports to do their bidding.

I’ve got an idea, but it may be more demanding on your network or disk performance. Is the Python running QML on your network, or installed locally on each machine? How about PyQt5?

What I’m thinking is that instead of launching QML once and separately, we’ll launch it when the user hits “Publish”. It’ll need to boot up Python and load PyQt5. On a local install, this isn’t a problem, it’ll be about 50-70 mb of data to read. But I’ve both experienced and gotten reports of network speeds where reading 50 mb can take tens of seconds.

With this solution then, albeit stable, we might have to look at a way of increasing performance of booting it up. Such as (1) only doing it once per Maya, (2) locally caching the Python and PyQt5 files, (3) incrementally loading necessary files on-the-fly or (4) installing a splash screen the user can look at while waiting.

This is where you can help. However long it takes to launch QML to reach a “ready” state at the moment, that’s how long the delay would be for a user seeing the GUI when hitting the button. Do you have a handle on how long that is, approximately?

Hi @derrick, I’ve put together a feature for this problem that I’d appreciate if you could try.

Let me know how that works for you.

Awesome, will do!

I’m somewhat embarrassed to say that my git-fu isn’t that great. I know how to clone the pyblish-qml repo but what’s the best way to grab the changes in this pull request as well?

Not a problem @derrick, cloning is sufficient in this case as well. You can clone from the source repository this PR is made from.

$ git clone https://github.com/mottosso/pyblish-qml.git
$ cd pyblish-qml
$ python -m pyblish_qml --demo

If you then use this repo, in place of your original, you’ll be good to go. Let me know if you need any other pointers. Would really like to have your eyes on this, for sake of performance.

Sorry @derrick I gave you the wrong info, you also had to check-out the branch with the changes.

$ git clone https://github.com/mottosso/pyblish-qml.git
$ cd pyblish-qml
$ git checkout popen
$ python -m pyblish_qml --demo

Let me know how it goes.

Hey @marcus,

Thanks so much for the instructions.

I got the pyblish-qml package set up and was having a lot of difficulties at first but it turned out that my pyblish-maya needed to be updated from 2.1.3 to 2.1.4

The load time for pyblish-qml is great, only takes about 2-3 seconds which is perfectly reasonable especially since the UI can be left open and refreshed as needed. The splash image is a nice tough!

The only problem I’m having now is that Maya will not close if pyblish-qml is left open. If I close the pyblish UI before exiting Maya, it works fine, but if pyblish is still open, Maya will hang until I manually kill the python.exe process in Task Manager.

I think we’re pretty close! If this Maya exit issue can be solved I’d say my team can move ahead with the Pyblish rollout which they’re very excited about.

Is there anything you’d like me to test? More info that might be useful?

That’s excellent @derrick thanks for letting me know of your findings! Hadn’t considered pyblish-maya needing an update, nor that Maya would freeze on closing while pyblish-qml was open. Investigating now.

Hey @marcus, any updates on this?

Not trying to rush you at all, it’s just that I will soon be passing ownership of this project onto someone else and I want to get them up to speed on where we’re at with the Pyblish roll out.

Hey @derrick, no problem you are right to ask. I expected to have solved by now, but it brought me to lower level issues that I have yet to figure out. But I am still working on it, if you would like to help then take a look at this thread and maybe you recognise the problem or know of someone who might.

https://groups.google.com/forum/m/#!topic/python_inside_maya/HTDpjcZHSow

Awesome, thanks for the update.
By the way, is there a function built-in to the pyblish-qml API for closing the UI, to complement the one used for showing it? And if so, would it also exit the process?

I’m wondering if we tried using the Maya exit callback I referenced in the first post to call the UI’s own “hide/close” functionality if that would be enough, versus trying to wrestle with blocking threads and such.

There is, and that was my first thought as well. The problem is there is no reliable way of triggering anything on Maya closing

To elaborate, processes generally don’t announce themselves closing, and when they do its highly platform specific. Python has its own cross-platform library called atexit with which you register a callback to be called when python is shutting down. The problem with that is twofold. Firstly, when a process is crashing, callbacks aren’t called and Maya can crash frequently enough to not have that aproach be reliable. Secondly, Python in Maya is embedded and not necessarily in control of its own life cycle. And from my experiments, atexit callbacks aren’t called even in ideal circumstance.

Now there are alternatives, one is to turn the thing around and have the child monitor its parent and self destruct on being left alone. But even there there are issues that make it difficult for a child to communicate with its parent, assumingly for security reasons.

So I could setup a heartbeat, with which the child continually asks the parent via the same mechanism it asks the parent to perform Pyblish tasks. The problem there is that when a parent is busy or hung, it may not be able to reply meaning a child could mistakenly self destruct.

So, all in all, not a trivial issue. But definitely solvable.

Ok, this rabbit hole keeps getting deeper and deeper. I’m going to consider this problem minor and push a version out today. I’ll be keeping my eyes open for a solution, but don’t hold your breath.

In practice, I’d imagine that closing Maya with the GUI open to be rare and on the occasions where it happens forcing Maya to quit is no showstopper.

Hope that makes sense.