def test_raise_thread_exception_on_nonexistent_thread(caplog): # When an interrupt is raised on a nonexistent thread threading.raise_thread_exception(-1, threading.Interrupt) # I expect a 'failed to set exception' critical message to be logged assert caplog.record_tuples == [ ("dramatiq.middleware.threading", logging.CRITICAL, ("Failed to set exception (Interrupt) in thread -1.")), ]
def abort(self, message_id: str) -> None: thread_id = self.abortables.pop(message_id, None) # In case the task was done in between the polling and now. if thread_id is None: return # pragma: no cover self.logger.info( "Aborting task. Raising exception in worker thread %r.", thread_id ) raise_thread_exception(thread_id, Abort)
def test_raise_thread_exception_on_nonexistent_thread(caplog): # When an interrupt is raised on a nonexistent thread thread_id = 2 ** 31 - 1 threading.raise_thread_exception(thread_id, threading.Interrupt) # I expect a 'failed to set exception' critical message to be logged expected_message = "Failed to set exception (Interrupt) in thread %d." % thread_id assert caplog.record_tuples == [ ("dramatiq.middleware.threading", logging.CRITICAL, expected_message), ]
def test_raise_thread_exception_unsupported_platform(caplog, monkeypatch): # monkeypatch fake platform to test logging. monkeypatch.setattr(threading, "current_platform", "not supported") # When raising a thread exception on an unsupported platform threading.raise_thread_exception(1, threading.Interrupt) # I expect a 'platform not supported' critical message to be logged assert caplog.record_tuples == [ ("dramatiq.middleware.threading", logging.CRITICAL, ("Setting thread exceptions (Interrupt) is not supported " "for your current platform ('not supported').")), ]
def _handle(self) -> None: message_ids = self.abortables.keys() if not message_ids: time.sleep(self.wait_timeout / 1000) return abort_keys = [self.id_to_key(id_) for id_ in message_ids] key = self.backend.wait_many(abort_keys, self.wait_timeout) if not key: return message_id = self.key_to_id(key) with self.lock: thread_id = self.abortables.pop(message_id, None) # In case the task was done in between the polling and now. if thread_id is None: return # pragma: no cover self.logger.info( "Aborting task. Raising exception in worker thread %r.", thread_id) raise_thread_exception(thread_id, Abort)
def test_raise_thread_exception(): # Given that I have a database caught = [] # And a function that waits for an interrupt def work(): try: for _ in range(10): time.sleep(.1) except threading.Interrupt: caught.append(1) # When I start the thread t = Thread(target=work) t.start() time.sleep(.1) # And raise the interrupt and join on the thread threading.raise_thread_exception(t.ident, threading.Interrupt) t.join() # I expect the interrupt to have been caught assert sum(caught) == 1