Почему мой демоноподобный скрипт Python запускается несколько раз?

#python #raspberry-pi

#python #raspberry-pi

Вопрос:

Я запускаю скрипт Python из скрипта bash при /etc/init.d использовании sudo /etc/init.d/fanservice.sh start (или остановке)

Он запускается и останавливается, как и ожидалось, и запускается при загрузке. Скрипт Python работает хорошо.

Однако в top или htop я вижу, что скрипт выполняется несколько раз.

Что может быть причиной этого и как мне это остановить? Кроме поиска других триггеров (я проверил, что в crontab нет старых ссылок на скрипт) Я не уверен, где еще искать.

Это /etc/init.d/fanservice.sh

Я запускаю скрипт Python от имени root, чтобы разрешить доступ к GPIO.

 #!/bin/sh

### BEGIN INIT INFO
# Provides:          myservice
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Put a short description of the service here
# Description:       Put a long description of the service here
### END INIT INFO

# Change the next 3 lines to suit where you install your script and what you want to call it
DIR=/home/pi
DAEMON=$DIR/fanservice.py
DAEMON_NAME=fanservice

# Add any command line options for your daemon here
DAEMON_OPTS=""

# This next line determines what user the script runs as.
# Root generally not recommended but necessary if you are using the Raspberry Pi GPIO from Python.
DAEMON_USER=root

# The process ID of the script when it runs is stored here:
PIDFILE=/var/run/$DAEMON_NAME.pid

. /lib/lsb/init-functions

do_start () {
    log_daemon_msg "Starting system $DAEMON_NAME daemon"
    start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --chuid $DAEMON_USER --startas $DAEMON -- $DAEMON_OPTS
    log_end_msg $?
}
do_stop () {
    log_daemon_msg "Stopping system $DAEMON_NAME daemon"
    start-stop-daemon --stop --pidfile $PIDFILE --retry 10
    log_end_msg $?
}

case "$1" in

    start|stop)
        do_${1}
        ;;

    restart|reload|force-reload)
        do_stop
        do_start
        ;;

    status)
        status_of_proc "$DAEMON_NAME" "$DAEMON" amp;amp; exit 0 || exit $?
        ;;

    *)
        echo "Usage: /etc/init.d/$DAEMON_NAME {start|stop|restart|status}"
        exit 1
        ;;

esac
exit 0
 

Скрипт Python использует WiringPi, GPIO, tach и Paho.mqtt для считывания температуры, установки скорости вентилятора, считывания скорости из тахометра, а затем отправки сообщения MQTT брокеру. Все, что содержится в цикле while True: цикл с time.sleep(58) в конце, поэтому я ожидаю, что «сервис» будет запускаться и повторяться каждые 58 секунд.

Он делает это, но каждую минуту или около того новый экземпляр появляется в top.

Если я проверю /var/run/fanservice.pid , где хранится PID скрипта, я увижу, что у него есть PID первого экземпляра.

Например, через 15 или 20 минут htop покажет скрипт, запущенный с идентификатором PID, который соответствует идентификатору, хранящемуся в файле PID, и этот процесс будет иметь время XX минут и секунд с момента загрузки. Тогда будет XX повторяющихся процессов со своими собственными PID, все со временем 00:00.00, и их количество будет соответствовать (я думаю) количеству минут с момента загрузки.

Любые советы приветствуются. Сценарий init.d — это тот, который я нашел в Интернете, не могу вспомнить где, но я думаю, что я, вероятно, каким-то образом его сломал! Тем не менее, я перешел к выполнению этих задач в цикле таймера, а не из cron, потому что скрипт Python не завершался после вызова cron. У меня также есть другие скрипты, работающие таким образом, которым требуется более быстрый цикл, чем минимум 1 минута от cron, поэтому я хотел бы узнать, как заставить это работать правильно.

Спасибо!

Комментарии:

1. Почему вы используете сценарии инициализации в стиле SysV? Даже если вы придерживаетесь крошечных, минимальных систем, все равно есть лучшие способы сделать это — если у вас нет или вы не хотите запускать systemd, взгляните на runit или его более современный кузен s6 . И если используемый вами дистрибутив отправляет systemd, то… что ж, он у вас уже есть, и вы оплачиваете расходы; с таким же успехом можно использовать его для того, что он делает хорошо.

2. (cron также очень ошибочен; реальная система контроля процессов может автоматически запускать перезапуск или другое желаемое / настроенное событие всякий раз, когда он получает SIGCHILD от вашего процесса, завершающего работу, поэтому он немедленно реагирует с нулевыми затратами на опрос; никаких sleep циклов нигде).

3. Спасибо, вместо этого я попробую systemd и обновлю!

4. Я успешно перешел на systemd, спасибо за совет. Однако существует та же проблема — через некоторое время выполняется несколько копий скрипта Python. Может ли быть так, что systemd обнаруживает, что мой скрипт не отвечает, и запускает новую копию?

5. Это интересный результат. Завершает ли основной PID и оставляет ли дочерние процессы запущенными? Какой тип службы вы указываете?