Как заставить диспетчер контекста Python перехватывать сигнал SIGINT или SIGTERM

Я выполняю потоковую передачу данных с помощью диспетчера контекста, чтобы закрыть соединение при выходе из программы. Я запускаю свою программу как демон в фоновом режиме.

Как я могу заставить диспетчер контекста обрабатывать случай, когда демон прерывается SIGINT или SIGTERM или любым сигналом прерывания, отправленным командой kill?

Я запускаю Python 3 на Raspberry Pi и Ubuntu.

Обновлять

Я видел это: Как записать SIGINT в Python? Что полезно, но я не уверен, как использовать это с диспетчером контекста python? т.е. скажем, у меня есть объект, который я создал как диспетчер контекста:

class Sensor:

    def __init__(self, name: str):
        self.name = name

    def __enter__(self):
        self._connect()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()

Я использую этот объект внутри скрипта, который запускается как демон. Есть ли питонический способ указать, что функция __ exit__ должна вызываться также в исключениях SIGINT и SIGTERM?

Извините, если вы не поняли, как работают исключения и прерывания сигнала в python, и что мой вопрос не имеет смысла


person gohu    schedule 29.06.2020    source источник
comment
Отвечает ли это на ваш вопрос? Как записать SIGINT в Python?   -  person mkrieger1    schedule 29.06.2020
comment
Не совсем, я обновил вопрос по этому поводу   -  person gohu    schedule 29.06.2020
comment
Разве ваш менеджер контекста уже не работает для SIGINT?   -  person Davis Herring    schedule 29.06.2020
comment
Вам необходимо зарегистрировать любую функцию, которую вы хотите вызвать, как обработчик сигнала, например self.close.   -  person mkrieger1    schedule 30.06.2020
comment
Да, и без этого он может уже работать так, как вы ожидаете, потому что это диспетчер контекста. Можете ли вы показать минимальный воспроизводимый пример, где сценарий не работает так, как вы ожидаете, когда вы используете команду kill?   -  person mkrieger1    schedule 30.06.2020
comment
Я пробовал кое-что, используя сигнал на своей стороне. Что делает его более сложным, так это то, что я использую потоки для потоковой передачи и записи данных. Я обновлю свой ответ, указав, что работает до сих пор, и посмотрю, есть ли лучшая идея попробовать   -  person gohu    schedule 30.06.2020


Ответы (1)


Вы можете создать внутренний метод (например, _handle_interrupt) для своего диспетчера контекста, который вызывает sys.exit(), и зарегистрировать его как обработчик сигнала после вызова __enter__:

class Sensor:

    def __init__(self, name: str):
        self.name = name

    def _handle_interrupt(self):
       sys.exit()  # will trigger a exception, causing __exit__ to be called

    def __enter__(self):
        signal.signal(signal.SIGINT, self._handle_interrupt)
        signal.signal(signal.SIGTERM, self._handle_interrupt)
        self._connect()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()

Вам также следует взглянуть на PEP 419, который может быть полезен для ваша установка. Что касается ваших требований в отношении многопоточности, трудно сказать без дополнительной информации.

person nehtor.t    schedule 12.08.2020
comment
Как это можно использовать с docs.python.org/3/library/? - person AlexM; 13.11.2020
comment
Думаю, вы можете использовать приведенный выше код и расширить ContextDecorator, что позволит вам использовать его как декоратор с любой функцией - person nehtor.t; 14.11.2020