Я использую python для создания скрипта, который запускается и взаимодействует с некоторыми процессами одновременно.Для этого я использую asyncio для реализации этого параллелизма.Основная проблема заключается в том, как запустить другую процедуру очистки при возникновении KeyboardInterrupt или SIGINT.
Вот пример кода, который я написал, чтобы показать проблему:
import asyncio
import logging
import signal
from time import sleep
class Process:
async def start(self, arguments):
self._process = await asyncio.create_subprocess_exec("/bin/bash", *arguments)
return await self._process.wait()
async def stop(self):
self._process.terminate()
class BackgroundTask:
async def start(self):
# Very important process which needs to run while process 2 is running
self._process1 = Process()
self._process1_task = asyncio.create_task(self._process1.start(["-c", "sleep 100"]))
self._process2 = Process()
self._process2_task = asyncio.create_task(self._process2.start(["-c", "sleep 50"]))
await asyncio.wait([self._process1_task, self._process2_task], return_when=asyncio.ALL_COMPLETED)
async def stop(self):
# Stop process
await self._process1.stop()
# Call a cleanup process which cleans up process 1
cleanup_process = Process()
await cleanup_process.start(["-c", "sleep 10"])
# After that we can stop our second process
await self._process2.stop()
backgroundTask = BackgroundTask()
async def main():
await asyncio.create_task(backgroundTask.start())
logging.basicConfig(level=logging.DEBUG)
asyncio.run(main(), debug=True)
Этот код создает фоновую задачукоторый запускает два процесса (в этом примере две команды bash sleep) и ожидает их завершения.Это работает нормально, и обе команды работают параллельно.
Основная проблема - процедура остановки.Я хотел бы запустить метод stop
, когда программа получает SIGINT или KeyboardInterrupt, который сначала останавливает process1, затем запускает метод очистки и затем останавливает process2.Это необходимо, потому что команда очистки зависит от process2.
Что я пробовал (вместо asyncio.run () и async main):
def main():
try:
asyncio.get_event_loop().run_until_complete(backgroundTask.start())
except KeyboardInterrupt:
asyncio.get_event_loop().run_until_complete(backgroundTask.stop())
main()
Это, конечно, нескольконе работает должным образом, потому что, как только возникает исключение KeyboardInterrupt, задача backgroundTask.start отменяется, и backgroundTask.stop запускается в главном цикле, поэтому мои процессы отменяются и не могут быть остановлены должным образом.
Так есть ли способ обнаружить KeyboardInterrupt без отмены текущего основного цикла и запустить вместо этого мой метод backgroundTask.stop?