LINUX.ORG.RU

Как правильно обрабатывать в программе завершение работы системы

 , ,


1

4

Как правильно обработать завершение работы в программе? Я написал скрипт на python, который управляет пинами Raspberry pi. Я знаю про сигнал SIGTERM, и я его обрабатываю и все работает корректно если его посылать процессу, но при выключении системы скрипт не завершается корректно. Он стоит в автозапуске в systemd и в логах я вижу, что при старте скрипта после обычного выключения ресурс в виде пинов не был освобожден. С чем может быть связана такая проблема? На малинке стоит Raspbian, на базе Debian 10 Buster. Костыли, пожалуйста, не предлагайте. По типу сделать скрипт для отключения этого скрипта и вызывать его при выключении. Нужно, чтобы при отключении или перезагрузке Raspberry скрипт управляющий вентилятором, сам корректно выключался.

Ответ на: комментарий от goingUp

[Unit] Description=A regulator fan RPM service. After=multi-user.target [Service] Type=simple ExecStart=/usr/bin/python3 -u /home/krauzer/Scripts/fan.py Restart=always [Install] WantedBy=multi-user.target

Krauzer
() автор топика

Я знаю про сигнал SIGTERM, и я его обрабатываю и все работает корректно если его посылать процессу, но при выключении системы скрипт не завершается корректно.

А точно корректно обрабатываешь?

hateyoufeel ★★★★★
()
Ответ на: комментарий от hateyoufeel

Да, если убить процесс, то он освобождает ресурс и пишет в логах что был пойман сигнал завершения, а если послать SIGKILL, то как раз происходит тоже самое как при перезагрузке. Единственное что, у меня не сохраняются логи journald до перезагрузки. Поэтому я не могу посмотреть, что процесс выводит при перезагрузке. Но при запуске ситуация точно такая же, как и при SIGKILL.

Krauzer
() автор топика
Ответ на: комментарий от Krauzer

Проверь сколько времени между SIGTERM и SIGKILL проходит. Systemd сначала присылает один, а потом другой, и возможно твой код почему-то подвисает где-то.

В юнит вроде можно прописать задержку между этими сигналами. Но я забыл как параметр называется.

hateyoufeel ★★★★★
()
Последнее исправление: hateyoufeel (всего исправлений: 1)
Ответ на: комментарий от hateyoufeel

А как это проверить? Я почитал документацию systemd, там сказано, что за задержку отвечает параметр TimeoutStopSec. Но я его не настраивал, а в конфигурационных файлах, судя опять же по документации, это время по умолчанию 90 секунд. Этого должно хватить за глаза. К слову мой скрипт после получения SIGTERM вызывает исключение, а обработчик этого исключения пишет в лог, что зафиксирован сигнал завершения и освобождает пины. Ничего лишнего и долгого. И при получении команды малинка моментально отправляется в перезагрузку или выключается. Никакого ожидания и подавно нет.

Krauzer
() автор топика

Может другой сигнал ловить?
Например SIGHUP:
https://askubuntu.com/questions/819730/no-sigterm-before-sigkill-shutdown-wit...

systemd (opposed to upstart in earlier Ubuntu verions) additionally sends SIGHUP on shutdown (and waits 90s instead of 10s before sending SIGKILL). I suggest to ignore SIGHUP or to handle SIGTERM and SIGHUP the same (idempotent) way.

Кто-то пишет, что надо вручную эмулировать:
https://stackoverflow.com/questions/58334551/sigterm-not-getting-trappped-on-...

It's not that it does not trap the signal but that the signal is not sent at that time. You have to configure systemd to do that for Your program.

Посмотри все сигналы:

man signal

Novator ★★★★★
()
Ответ на: комментарий от Krauzer

А как это проверить?

Ну, пиши в файлик на каждый сигнал. Тут без твоего кода, на самом деле, мало что можно сказать. Если запилишь минимальный пример, где это воспроизводится, будет куда проще.

hateyoufeel ★★★★★
()
Ответ на: комментарий от hateyoufeel

Ну, пиши в файлик на каждый сигнал.

С SIGKILL будет нетривиально, да… Но в целом идея правильная.

bugfixer ★★★★★
()
Ответ на: комментарий от Krauzer

Единственное что, у меня не сохраняются логи journald до перезагрузки. Поэтому я не могу посмотреть, что процесс выводит при перезагрузке. Но при запуске ситуация точно такая же, как и при SIGKILL.

Включи, потом выключишь. Для начала нужно разобраться, это твой скрипт что-то неправильно обрабатывает, или системд ему не посылает сигнал.

goingUp ★★★★★
()
Ответ на: комментарий от Krauzer

Единственное что, у меня не сохраняются логи journald до перезагрузки. Поэтому я не могу посмотреть, что процесс выводит при перезагрузке

Попробуй стопнуть юнит без перезагрузки и посмотреть, как он отреагирует

systemctl stop <unitname>
grazor ★★
()
Ответ на: комментарий от Novator

У человека на stackoverflow такая же проблема, я этого не нашел сам когда искал в поиске, но тем не менее она не решена. Я пробовал обрабатывать и SIGHUP, результат тот же. В мане ничего полезного по моей ситуации не нашел.

Krauzer
() автор топика
Ответ на: комментарий от grazor

Пробовал и не раз. Все работает как ожидается, если не перезагружать.

Krauzer
() автор топика
Ответ на: комментарий от goingUp

Я разобрался и включил логи до перезагрузок. Выяснилась интересная ситуация. Скрипт сообщает что он ловит сигнал и корректно завершается, но при включении пишет, что пины не освобождены. Т.е. проблема какая-то с освобождением пинов при выключении. Потому что при обычной остановке юнита они освобождаются корректно.

Krauzer
() автор топика
Ответ на: комментарий от Krauzer

при включении пишет, что пины не освобождены. Т.е. проблема какая-то с освобождением пинов при выключении

Возможно, модуль ядра, который управляет пинами, к моменту завершения скрипта успевает выгрузится, т.к. тоже получил сигнал перезагрузки.

Novator ★★★★★
()
Ответ на: комментарий от Novator

Да, возможно. Надо проверить. Буду сейчас искать информацию об этом и о библиотеке управляющей пинами.

Krauzer
() автор топика
Ответ на: комментарий от Krauzer

К сожалению, это не увенчалось успехом. Найти решение проблемы не удалось. По всей видимости у библиотеки возникают какие-то проблемы при освобождении пинов в момент перезагрузки. И отловить это я не могу. Нельзя ли как-то настроить systemd, чтобы он соблюдал порядок при выключении процессов? Как вообще корректно решать такую проблему? Ведь бредовая ситуация получается. Мне нужно освободить ресурс, который уже недоступен. Такое же не только с пинами может быть.

Krauzer
() автор топика
Ответ на: комментарий от Krauzer

чувак, тебе реально влом изучить примитивнейший «язык системного программирования це» и не мучать пины процессора своими питоновыми скриптами? от це контроллеру твоему только лучше станет.

alysnix ★★★
()
Ответ на: комментарий от alysnix

У меня есть простая задача, которую я уже решил. Я и так больше времени потратил на то, чтобы изучить инструменты системы по типу systemd, чем писал свой код. А ты мне предлагаешь изучить вообще другой язык, чтобы все работало как надо. К тому же я не понимаю с чего вдруг на другом языке оно будет успевать завершаться? Значит там будет иной подход. И ты мне предлагаешь вот так заморочиться ради такой простой вещи? У меня скрипт строк 40. Я вентилятором управляю. У меня изначально и так не было желания изучать всю систему досконально, чтобы вот такая простая фигня заработала. Поэтому предложение такое себе.

Krauzer
() автор топика
Ответ на: комментарий от Krauzer

У меня скрипт строк 40.

у тебя не скрипт в 40 строк, а огромный интерпретатор питона со своими тараканами, и завершаешь ты его, по сути, а не скрипт.

а на си у тебя только твой откомпилированный код, и размер задачи пара килобайт. вместо мегабайт питона с его рантаймом и интерпретатором.

alysnix ★★★
()
Ответ на: комментарий от goingUp

Проверил, нет, не ок. Очень странно. Та же проблема, даже если остановить юнит и перезагрузиться. Но если остановить, а потом запустить без перезагрузки, то все ок.

Krauzer
() автор топика
Ответ на: комментарий от Krauzer

Ну в общем проблема оказалась не там где ты думал, и даже не во втором возможном месте. Все как обычно.

Может пины занимает какая-то другая софтина при старте?

goingUp ★★★★★
()
Последнее исправление: goingUp (всего исправлений: 1)
Ответ на: комментарий от goingUp

Ну да. Было бы все просто, я бы не пошел на форум. Проблема решена. Оказалось и вправду кое-что системное занимает пины. Когда я настраивал работу вентилятора еще до того, как написал скрипт, я наткнулся на настройку вентилятора в Raspberry Pi Configuration. И я игрался с этим там. У меня ничего не заработало и я подумал, что эта штука не работает. Я реально не знаю как это должно работать, но я не отключил настройку вентилятора и эта системная штука и занимала пин. Теперь когда я ее отключил все работает как надо. Если кто знает зачем нужна та системная настройка, то было бы интересно узнать. Я искал в интернете информацию по этому поводу и не нашел. Ну а тему можно считать закрытой.

Krauzer
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.