5

I have been writing a Nuke render manager in Python and came across a problem: nuke.cancel() doesn't seem to work right. My python script creates a main class and connects to a server (written in Java) and then enters an infinite loop, each time getting a new task (in the form of a JSON object). Each loop it gets opens a script? finds the write nodes and executes them. To report progress back to the server I have added callbacks: nuke.addBeforeFrameRender(lambda: self._pre_frame_render()) and nuke.addAfterFrameRender(lambda: self._post_frame_render()) where

def _pre_frame_render(self):
    self._host_socket.send(struct.pack('>b', 1))
    self._host_socket.send(struct.pack('>i', nuke.frame()))

def _post_frame_render(self):
    self._host_socket.send(struct.pack('>b', 2))
    self._host_socket.send(struct.pack('>i', nuke.frame()))

To enable a cancel method on the server, I have a separate thread that runs while the rendering is active and waits for a 'cancel' request

class CancelHandler(threading.Thread):
    def __init__(self, input_socket, cancel_callback):
        threading.Thread.__init__(self)
        self.cancel_set = threading.Event()
        self.run_set = threading.Event()
        self._input_socket = input_socket
        self._cancel_callback = cancel_callback

    def run(self):
        while True:
            if self.run_set.is_set():
                msg_raw = recv_msg(self._input_socket)
                msg = json.loads(msg_raw)
                if 'mode' in msg and msg['mode'] == 'cancel':
                    print msg_raw
                    self.cancel_set.set()
                    self.run_set.clear()
                    self._cancel_callback()

The cancel_callback is defined as

def _cancel_callback(self):
        nuke.cancel()
        self._is_canceled = True

Before the loop starts I start the CancelHandler thread and on each iteration the run_set action is set, and after - cleared to let the main thread communicate. In between that at different stages I check if cancel_set has been set in case a 'cancel' request has arrived.

All of the above seems to work fine except for one thing: nuke.execute() does absolutely nothing - the render just continues. I have tried putting it in the nuke.addBeforeFrameRender and nuke.addAfterFrameRender callbacks but that does nothing. Also I thought it might be executing in the wrong thread so I tried nuke.executeInMainThread(nuke.cancel) with no luck.

The documentation reads:

execute(nameOrNode, start, end, incr, views, continueOnError= False) ... If Nuke is run with the GUI up, this will pop up a progress meter. If the user hits the cancel button this command will return 'cancelled' error. If Nuke is run from the nuke command line (ie nuke was started with the -t switch) execute() prints a text percentage as it progresses. If the user types ^C it will aborting the execute() and return a 'cancelled' error.

so I tried replacing nuke.cancel() with os.kill(os.getpid(), signal.CTRL_C_EVENT) That actually stopped the render but execute() never returned so the script couldn't continue

Since execute() should

return a 'cancelled' error

I tried to catch the nuke.CancelledError exception both from the execute() and the os.kill(os.getpid(), signal.CTRL_C_EVENT) code but it wasn't thrown.

Curiously, when I ran this callback:

def _cancel_callback(self):
        self._is_canceled = True
        os.kill(os.getpid(), signal.CTRL_C_EVENT)
        print "Cancelled"

the print line got executed

I am fairly new to python so it might be a noob's mistake but does anyone know what I might be doing wrong or if it's a bug in the API? Or maybe someone cam come up with a better solution to the problem - that would be greatly appreciated!

So far the only way out of this situation I see is to simply shut down the worker process and then launch a new one, but that would be kind of an ugly thing to do each time someone wants to cancel a job.

Using Nuke 9.0v3 Full source code can be found at https://bitbucket.org/andrey_glebov/nukerendermanager/src in PYTHON directory

4

1 回答 1

0

以下命令取消了一个Progress窗口,因此它也停止了渲染过程。

nuke.toNode('Write1')['disable'].setValue(1)
于 2022-01-09T18:35:22.903 回答