diff --git a/python/tk_desktop/rpc.py b/python/tk_desktop/rpc.py index b8216a43..87020073 100644 --- a/python/tk_desktop/rpc.py +++ b/python/tk_desktop/rpc.py @@ -194,6 +194,13 @@ class RPCServerThread(threading.Thread): list/dictionary are treated as args/kwargs for the function call. """ + # FIXME: Any errors raised here when closing won't actually be caught by + # our tests, because the error happens in a separate thread. This can be solved + # by catching and storing the exception and then raising it in the join method + # as suggested here: https://stackoverflow.com/a/31614591/4223964 + # This is currently not implemented because it raises errors in our tests + # that we at the time of writing don't have time to fix, but have no impact on user experience. + # timeout in seconds to wait for a request LISTEN_TIMEOUT = 2 @@ -256,7 +263,7 @@ def wrapper(*args, **kwargs): def run(self): """ Run the thread, accepting connections and then listening on them until - they are closed. Each message is a call into the function table. + they are closed. Each message is a call into the function table. """ logger.debug("server listening on '%s'", self.pipe) while self._is_closed is False: @@ -278,10 +285,17 @@ def run(self): raise ready = False else: - # can use select on osx and linux - (rd, _, _) = select.select( - [self.server._listener._socket], [], [], self.LISTEN_TIMEOUT - ) + # Can use select on OSX and Linux. + try: + (rd, _, _) = select.select( + [self.server._listener._socket], [], [], self.LISTEN_TIMEOUT + ) + except select.error as e: + if "Bad file descriptor" in e.args: + # The socket was likely closed during this iteration of the loop + # so we should break out of the loop. + break + raise ready = len(rd) > 0 if not ready: diff --git a/tests/test_rpc.py b/tests/test_rpc.py index 39c6fc0a..c531d03f 100644 --- a/tests/test_rpc.py +++ b/tests/test_rpc.py @@ -128,6 +128,11 @@ def server(fake_engine, request): :returns: A RPCServerThread instance. """ + + # FIXME: Any errors raised here when closing won't actually be caught by + # our tests, because the error happens in a separate thread. + # See the FIX ME in the RPCServerThread class for further details. + server = RPCServerThread(fake_engine) server.register_function(fake_engine.pass_arg) server.register_function(fake_engine.pass_named_arg)