| 62 | |
| 63 | |
| 64 | class WorkerProcess(Process): |
| 65 | instances = [] |
| 66 | |
| 67 | def __init__(self, pid=None): |
| 68 | Process.__init__(self) |
| 69 | self.task_queue = Queue() |
| 70 | self.result_queue = Queue() |
| 71 | self.daemon = ( |
| 72 | True |
| 73 | ) # when parent process is killed, sub/childprocess get also killed |
| 74 | self.instances.append(self) |
| 75 | # used to detect single process exercise |
| 76 | self._identity = (pid,) if pid else (random.randint(0, int(1e12)),) |
| 77 | |
| 78 | def get_shell(self): |
| 79 | return create({}) |
| 80 | |
| 81 | def run(self): |
| 82 | shell = self.get_shell() |
| 83 | while True: |
| 84 | output = [] |
| 85 | with CaptureErrors(output): |
| 86 | next_task = self.task_queue.get() |
| 87 | answer = next_task(shell) |
| 88 | if len(output) > 0: # means backend error happened |
| 89 | answer = output |
| 90 | output = [] |
| 91 | with CaptureErrors(output): |
| 92 | self.result_queue.put_nowait(answer) |
| 93 | if len(output) > 0: # means backend error happened |
| 94 | self.result_queue.put_nowait(output) |
| 95 | if isinstance(next_task, TaskKillProcess): |
| 96 | break # break while loop -> we do not wait upon new task |
| 97 | return |
| 98 | |
| 99 | def executeTask(self, task): |
| 100 | self.task_queue.put_nowait(task) |
| 101 | return self.result_queue.get() # wait and fetches next item in queue |
| 102 | |
| 103 | def kill(self): |
| 104 | try: |
| 105 | if self.is_alive(): |
| 106 | self.executeTask(TaskKillProcess()) |
| 107 | self.join(timeout=3.0) |
| 108 | if self.is_alive(): |
| 109 | self.terminate() |
| 110 | self.join(timeout=3.0) |
| 111 | if self in self.instances: |
| 112 | self.instances.remove(self) |
| 113 | finally: |
| 114 | pass |
| 115 | # python 3.7: |
| 116 | # self.close() |
| 117 | |
| 118 | @classmethod |
| 119 | def kill_all(cls): |
| 120 | for instance in list(cls.instances): |
| 121 | instance.kill() |
no outgoing calls
no test coverage detected