Как заставить скрипт Python работать как сервис?

Я хочу запустить скрипт Python на сервере CENTOS:

#!/usr/bin/env python
import socket
try:    
    import thread 
except ImportError:
    import _thread as thread #Py3K changed it.
class Polserv(object):
    def __init__(self):
        self.numthreads = 0
        self.tidcount   = 0
        self.port       = 843
        self.sock       = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind(('100.100.100.100', self.port))
        self.sock.listen(5)
    def run(self):
        while True:
            thread.start_new_thread(self.handle, self.sock.accept()) 
    def handle(self,conn,addr):
        self.numthreads += 1
        self.tidcount   += 1
        tid=self.tidcount
        while True:
            data=conn.recv(2048)
            if not data:
                conn.close()
                self.numthreads-=1
                break
            #if "<policy-file-request/>\0" in data:
            conn.sendall(b"<?xml version='1.0'?><cross-domain-policy><allow-access-from domain='*' to-ports='*'/></cross-domain-policy>")
            conn.close()
            self.numthreads-=1
            break
        #conn.sendall(b"[#%d (%d running)] %s" % (tid,self.numthreads,data) )
Polserv().run()

Я использую $ python flashpolicyd.py, и он отлично работает... Вопрос в том, как сохранить этот скрипт даже после закрытия терминала (консоли)?


person Filipe Tagliacozzi    schedule 07.05.2013    source источник
comment
возможный дубликат Как чтобы скрипт Python работал как служба или демон в Linux   -  person piokuc    schedule 07.05.2013
comment
Не точная копия - связанный с вопросом вопрос о повторяющейся задаче, это о сетевом демоне; решением другого был cron, решением этого является inetd (или эквивалент).   -  person Robᵩ    schedule 07.05.2013


Ответы (5)


Я использую это код для демонизации моих приложений. Это позволяет вам start/stop/restart скрипт использовать следующие команды.

python myscript.py start
python myscript.py stop
python myscript.py restart

В дополнение к этому у меня также есть скрипт init.d для контролировать мою службу. Это позволяет автоматически запускать службу при загрузке операционной системы.

Вот простой пример, чтобы начать. Просто переместите свой код внутрь класса и вызовите его из функции run внутри MyDeamon.

import sys
import time

from daemon import Daemon


class YourCode(object):
    def run(self):
        while True:
            time.sleep(1)


class MyDaemon(Daemon):
    def run(self):
        # Or simply merge your code with MyDaemon.
        your_code = YourCode()
        your_code.run()


if __name__ == "__main__":
    daemon = MyDaemon('/tmp/daemon-example.pid')
    if len(sys.argv) == 2:
        if 'start' == sys.argv[1]:
            daemon.start()
        elif 'stop' == sys.argv[1]:
            daemon.stop()
        elif 'restart' == sys.argv[1]:
            daemon.restart()
        else:
            print "Unknown command"
            sys.exit(2)
        sys.exit(0)
    else:
        print "usage: %s start|stop|restart" % sys.argv[0]
        sys.exit(2)

Выскочка

Если вы используете операционную систему, использующую Upstart (например, CentOS 6), вы также можете использовать Upstart для управления службой. Если вы используете Upstart, вы можете оставить свой скрипт как есть и просто добавить что-то подобное в /etc/init/my-service.conf

start on started sshd
stop on runlevel [!2345]

exec /usr/bin/python /opt/my_service.py
respawn

Затем вы можете использовать start/stop/restart для управления вашим сервисом.

e.g.

start my-service
stop my-service
restart my-service

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

Система

Если вы используете операционную систему, использующую Systemd (например, CentOS 7), вы можете взглянуть на следующий Ответ StackOverflow.

person eandersson    schedule 07.05.2013
comment
Хорошо.. но я не вижу, как использовать этот класс в моем сценарии... вы можете научить? - person Filipe Tagliacozzi; 07.05.2013
comment
как бы вы использовали скрипт init.d с MyDaemon? Предполагая, что Daemon разветвляет процесс MyDaemon, эта возможность может разветвить новый процесс, а затем он может попытаться перезапуститься, потому что он думает, что сценарий завершен (что приводит к тысячам запущенных процессов python). Можете ли вы предоставить быстрый/простой пример init.d с простым python Dameon? - person sigi; 10.03.2015
comment
@sigi: Если сценарий фактически не завершится, демон python должен предотвратить запуск любых новых процессов, но вы всегда можете просто проверить файл pid в своем сценарии init.d. Я могу обновить ответ, когда у меня будет время через день или два, если вам нужен правильный пример. - person eandersson; 11.03.2015
comment
@eandersson: я думал, что скрипт демона Python, на который вы ссылались, дважды выполняет разветвление процесса, и, следовательно, init.d (Upstart), я думаю, должна иметь команду ожидаемого демона в файле .conf или что-то в этом роде ... Я' Мне просто интересно, как бы вы заставили свой файл Upstart .conf искать простой демон python, используя сценарий демонизатора, на который вы ссылались, т.е. простой пример того, как вы используете сценарий init.d для управления вашим сервисом, был бы действительно замечательным... Спасибо. - person sigi; 12.03.2015
comment
Если вы используете Upstart, вероятно, лучше просто использовать сценарии Upstart и полностью пропустить мое решение. Это очень просто и сделает всю тяжелую работу за вас. См. этот ответ Stackoverflow для получения дополнительной информации: stackoverflow. ком/вопросы/17747605/ - person eandersson; 13.03.2015
comment
это больше не работает, невозможно импортировать Daemon из daemon. - person Thijs; 02.12.2015
comment
@Thijs это не имеет ничего общего с этим кодом. Скорее всего, в каталоге отсутствует файл init.py или что-то подобное. - person eandersson; 02.12.2015
comment
@eanandersson, извините за мой комментарий ранее, но этот демон не работает, когда демонизируемый скрипт импортирует многопроцессорный модуль. Некоторый конфликт возникает при создании процесса с многопроцессорностью внутри этого демона, выдающего ошибку, которая может присоединиться только к дочернему процессу. Пожалуйста, протестируйте этот демон с любым базовым примером многопроцессорного модуля. - person MohitC; 27.06.2016
comment
@MohitC: К сожалению, это немного не по теме. Я бы порекомендовал вам открыть новый вопрос специально для демонизации многопроцессорного приложения. - person eandersson; 30.06.2016
comment
@eandersson Спасибо за хороший ответ, я пытаюсь создать скрипт init.d для управления своим сервисом. В документах init.d упоминается файл PID. это PID и daemon = MyDaemon('/tmp/daemon-example.pid') одинаковы? и как передать аргумент запуска/остановки из initd. скрипт на скрипт python - person ShivaPrasad; 12.09.2019

Предлагаю две рекомендации:

надзиратель

1) Установите пакет supervisor (более подробные инструкции здесь):

sudo apt-get install supervisor

2) Создайте файл конфигурации для вашего демона по адресу /etc/supervisor/conf.d/flashpolicyd.conf:

[program:flashpolicyd]
directory=/path/to/project/root
environment=ENV_VARIABLE=example,OTHER_ENV_VARIABLE=example2
command=python flashpolicyd.py
autostart=true
autorestart=true

3) Перезапустите supervisor, чтобы загрузить новый .conf

supervisorctl update
supervisorctl restart flashpolicyd

systemd (если в настоящее время используется вашим дистрибутивом Linux)

[Unit]
Description=My Python daemon

[Service]
Type=simple
ExecStart=/usr/bin/python3 /opt/project/main.py
WorkingDirectory=/opt/project/
Environment=API_KEY=123456789
Environment=API_PASS=password
Restart=always
RestartSec=2

[Install]
WantedBy=sysinit.target

Поместите этот файл в /etc/systemd/system/my_daemon.service и включите его с помощью systemctl daemon-reload && systemctl enable my_daemon && systemctl start my_daemon --no-block.

Для просмотра журналов:

systemctl status my_daemon

person pztrick    schedule 07.05.2013
comment
супер простой способ :) - person Samad; 03.05.2017
comment
Привет @Freude! Я добавил в свой ответ конфигурацию демона systemd. Многие Linux теперь поставляются с systemd для сценариев инициализации, и конфигурация очень похожа на supervisord. - person pztrick; 18.11.2017
comment
Файл .service должен быть создан в /lib/systemd/system/ в CentOS - person Koorosh Ghorbani; 20.03.2018
comment
можно ли прописать относительные пути в execstart? - person ScipioAfricanus; 07.10.2019
comment
Используя этот подход systemd, я мог заставить демона работать, но он не может запускаться после перезагрузки со следующей ошибкой: Job active_controller.service/start удален, чтобы прервать цикл заказа, начинающийся с sysinit.target/start - person PouJa; 01.10.2020

Мой непитоновский подход будет использовать суффикс &. Это:

python flashpolicyd.py &

Чтобы остановить скрипт

killall flashpolicyd.py

также конвейер и суффикс с disown поместит процесс в суперродительский (верхний):

python flashpolicyd.pi & disown
person shookees    schedule 04.05.2014
comment
Последний не работает (Ubuntu 16.04): -bash: syntax error near unexpected token '|' - person the_nuts; 08.08.2016

сначала импортируйте модуль ОС в свое приложение, чем с использованием функции getpid, получите приложение pid и сохраните его в файле. Например:

import os
pid = os.getpid()
op = open("/var/us.pid","w")
op.write("%s" % pid)
op.close()

и создайте файл bash в /etc/init.d путь: /etc/init.d/servername

PATHAPP="/etc/bin/userscript.py &"
PIDAPP="/var/us.pid"
case $1 in 
        start)
                echo "starting"
                $(python $PATHAPP)
        ;;
        stop)
                echo "stoping"
                PID=$(cat $PIDAPP)
                kill $PID
        ;;

esac

теперь вы можете запускать и останавливать ваше приложение с помощью команды down:

имя сервера службы остановить имя сервера службы начать

or

/etc/init.d/имя_сервера остановить /etc/init.d/имя_сервера запустить

person Arsalan    schedule 04.05.2014

для моего скрипта Python я использую...

Чтобы НАЧАТЬ скрипт Python:

start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --exec $DAEMON

Чтобы ОСТАНОВИТЬ скрипт Python:

PID=$(cat $PIDFILE)
kill -9 $PID
rm -f $PIDFILE

P.S.: извините за плохой английский, я из ЧИЛИ :D

person Rodrigo Navarrete    schedule 11.07.2016