async def _signal_and_wait(self, signum): """ Send a SIGTERM or SIGKILL to the child process & reap it. - Send the signal to the process - Make sure we don't restart it when it stops - Wait for it to stop - Remove signal handler for it after we are done. """ # Aquire lock to modify process sate async with self._proc_lock: # Don't yield control between sending signal & calling wait # This way, we don't end up in a call to _restart_process_if_needed # and possibly restarting. We also set _killed, just to be sure. self.proc.send_signal(signum) self._killed = True # We cancel the restart watcher & wait for the process to finish, # since we return only after the process has been reaped self._restart_process_future.cancel() await self.proc.wait() self.running = False # Remove signal handler *after* the process is done atexitasync.remove_handler(self._handle_signal)
async def _restart_process_if_needed(self): """ Watch for process to exit & restart it if needed. This is a long running task that keeps running until the process exits. If we restart the process, `start()` sets this up again. """ retcode = await self.proc.wait() # FIXME: Do we need to aquire a lock somewhere in this method? atexitasync.remove_handler(self._handle_signal) self._debug_log('exited', '{} exited with code {}', {'code': retcode}, self.name, retcode) self.running = False if (not self._killed) and (self.always_restart or retcode != 0): await self.start()