Создание демона на python

Легко настраиваемый python daemon

Дальше я попробую описать логику работы всех трех.

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

Собственно в первом файлике описывать толком нечего: Это почти неизменные три класса, взятые из этой статьи. Из изменений там только то, что к самому демону был прикреплен класс обработчик сигналов, и добавление сигналов в список обрабатываемых было вкручено в собственно процедуру демонизации.

Вторая часть будет чуть интереснее. Там присутствует три класса:
1) SigFunctionsCon — содержит реакцию на сигналы. При инициализации получает экземпляр демона, чтобы уметь обращаться к его методам. Каждый метод должен соответствовать сигналу, который он обрабатывает названием. Например так:

def SIGTERM(self): sys.stderr.write("BB!\n") sys.exit(0) 

Внутренние методы и поля могут быть какими угодно.

2)ReactFunctionCon — содержит реакцию на консольные команды. При инициализации так же получает демона. Каждый метод по названию должен соответствовать команде на которую он будет реагировать и может принимать аргументы (то, что собственно идет за командой в командной строке). Например:

 def stmess(self,message): print message self.__ourdaemon.start()

3)StatCon — содержит всякие статические настройки демона. На данный момент выглядит так:

class StatCon: Help = "Autmation has be applied to distribution sistem feeder for a long time, aspecially as related to protection and the restoration of some parts of the feeder." def run(self): while(True): time.sleep(1) PidFile = "/tmp/daemon-naprimer.pid" Inputter = "/dev/null" Outputter = "/dev/null" Errorer = "/home/espresso/lid"

Соответственно —
Хелп строка, выводимая при неправильной передаче аргументов в какую-либо функцию (Возможно следует сделать команду хелп по умолчанию, которая выводит это сообщение?).
Метод run — собственно то, для чего все затевалось — то, что демон делает.
Адрес pid файла — для хранения процесса и все такое.
Ввод, вывод, ошибки — логгирование и прочее. По умолчанию отсылается в /dev/null

Читайте также:  Html appear on click

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

Ну и собственно вопросы:
Что не так, что не очень так?
Как по вашему следует ли как-то приписывать к этому GPL, или не стоит больгеносить, и все это слишком несерьезно?
Достаточно ли адекватно я указал предыдущих авторов?

Источник

Создание демона Python с использованием Systemd

Создание демона Python с использованием Systemd

Недавно у меня возникла задача создать демон (фоновое приложение) реализованный на Python в системе Linux использующей Systemd . В поисках современного решения и родилась данная статья. Ранее для реализации демона выполнялась «демонизация» приложения Python, зачастую с помощью библиотеки python-daemon

(opens new window) . Даже была создана спецификация pep-3143

(opens new window) для реализации демонов. Но на текущий момент времени с использованием Systemd нет необходимости демонизировать наше Python приложение, достаточно корректно описать его запуск в юните. Для начала рассмотрим как работает Systemd .

Все операции указанные в данной статье выполнялись в окружении Linux Ubuntu 20, с установленным Python 3.8.

# Systemd Unit

  • /usr/lib/systemd/system/ — юниты из установленных пакетов, такие как nginx, postgreee и др.
  • /run/systemd/system — юниты созданные в runtime
  • /etc/systemd/system — юиниты, созданные администратором, в основном пользовательские юниты должны храниться здесь.

Для создания юнита нам необходимо описать 3 секции: [Unit], [Service], [Install] Основные переменные блока [Unit]:

[Unit] Descripiton=Unit Descripion After=syslog.target After=network.target After=nginx.service After=mysql.service Requires=mysql.service Wants=redis.service 
  • Description — описание юнита
  • After — указывает, что юнит должен быть запущен после группы указанных сервисов
  • Requires — узказывает, что для запуска юнита требуется запущенный сервис mysql , запуск нашего сервиса выполняется паралллельно с требуемым ( mysql ), если требуемый не указан в After
  • Wants — описательная переменная, показывающая, что для запуска сервиса желателен запущенный сервис redis
[Service] Type=simple PIDFile=/var/lib/service.pid WorkingDirectory=/var/www/myapp User=user Group=user Environment=STAGE_ENV=production OOMScoreAdjust=-100 ExecStart=/my_venv/bin/python my_app.py --start ExecStop=/my_venv/bin/python my_app.py --stop ExecReload=/my_venv/bin/python my_app.py --restart TimeoutSec=300 Restart=always 
  • Type — тип запуска: simple (по умолчанию) запускает службу незамедлительно при этом процесс не должен разветвляться, не подходит если другие службы зависят от очередности при запуске данной службы; forking — служба запускается однократно и процесс разветвляется с завершением родительского процесса; другие типы можно рассмотреть по ссылке ниже.
  • PIDFile — позволяет задать место нахождения pid файла
  • WorkingDirectory — указывает рабочий каталог приложения, если указан то ExecStart|Stop|Reload запускаются из этого каталога, т.е. my_app.py станет /var/www/myapp/my_app.py
  • User, Group — соответственно пользователь и группа под которыми будет запущен сервис.
  • Environment — переменные окружения
  • OOOMSCoreAdjust — запрет на kill сервиса вследствие нехватки памяти и срабатывания механизма ООМ: -1000 полный запрет, -100 понижает вероятность.
  • ExecStart|Stop|Reload — команды запуска, останова, перезагрузки сервиса, команда должна использовать абсолютный путь к исполняемому файлу.
  • Timeout — время ожидания systemd отработки команд Start|Stop в сек.
  • Restart — перезапуск сервиса если он упадет.
[Install] WantedBy=multi-user.target 
  • WantedBy — уровень запуска нашего сервиса, mulit-user.target или runlevel3.target соответствует runlevel=3 «Многопользовательский режим без графики»

Размещаем данный файл с указанными секциями в директории /etc/systemd/sysmtem/.service

systemctl -l status test_unit 
systemctl start test_unit 

При внесении изменений в наш сервис перегружаем его:

# Python приложение

Разобрав как работает Systemd можем приступить к созданию нашего сервиса. Для ознакомления создадим приложение Python которое будет выводить сообщения в log файл test_daemon.py :

import time import argparse import logging logger = logging.getLogger('test_daemon') logger.setLevel(logging.INFO) formatstr = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' formatter = logging.Formatter(formatstr) def do_something(): """ Здесь мы только лишь пишем сообщение в Log, но можем реализовать абсолютно любые задачи выполняемые в фоне. """ while True: logger.info("this is an INFO message") time.sleep(5) if __name__ == "__main__": parser = argparse.ArgumentParser(description="Example daemon in Python") # Мы можем заменить default или запускать приложение с указанием нахождения # log файла, через параметр -l /путь_к_файлу/файл.log parser.add_argument('-l', '--log-file', default='/home/user/test_daemon.log') args = parser.parse_args() fh = logging.FileHandler(args.log_file) fh.setLevel(logging.INFO) fh.setFormatter(formatter) logger.addHandler(fh) do_something() 

Проверим работоспособность нашего скрипта:

Проверим что log-файл создан и в него пишутся сообщения:

tail -f /home/user/test_daemon.log 

Теперь создадим юнит Systemd для запуска демона. В директории /etc/systemd/system файл test_daemon.service с содержанием:

[Unit] Description=Test daemon After=syslog.target [Service] Type=simple User=user Group=user WorkingDirectory=/home/user/ ExecStart=/usr/bin/python3 test_daemon.py [Install] WantedBy=multi-user.target 

В данном юните следует изменить пользователя и группу User , Group на вашего пользователя. Также указать в качестве рабочего каталога WorkingDirectory абсолютный путь к директории где находится файл test_daemon.py.

В случае использования venv в параметре ExecStart следует указать путь к python внутри venv , т.е. заменть /usr/bin/python3 на /venv/bin/python

Проверяем статус нашего сервиса:

systemctl -l status test_daemon 
systemd enable test_daemon 
systemctl start test_daemon 

Проверим отображение данных в логе:

tail -f /home/user/test_daemon.log 

Наш демон заработал, но осталась не решенной еще одна задача. Зачастую при остановке нашего демона требуется выполнить каие либо задачи (сохранить состояние приложения, отправить уведомление, выполнить очистку данных и т.п.), но на текущий момент при останове наш демон просто закрывается.

# Обработка сигналов завершения

В стандартной библиотеке Pyhton реализован модуль sygnal позволяющий обрабатывать сигналы UNIX-based операционной системы. Полный перечень сигналов можно посмотреть по команде:

Демон Systemd при выполнении операции останова демона отправляет изначально сигнал 15 (SIGTERM) — нормальный останов процесса. По умолчанию если в течение 30 сек. не будет получен сигнал выхода приложения будет отправлен сигнал жесткого завершения процесса 9 (SIGKILL) .

Таким образом в нашем приложении необходимо предусмотреть обработчик сигнала 15 (SIGTERM) , как результат наш скрипт test_daemon.py примет следующий вид:

import time import argparse import logging import sys import signal logger = logging.getLogger('test_daemon') logger.setLevel(logging.INFO) formatstr = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' formatter = logging.Formatter(formatstr) def terminate(signalNumber, frame): """ Здесь мы можем обработать завершение нашего приложения Главное не забыть в конце выполнить выход sys.exit() """ logger.info(f'Recieved signalNumber>') sys.exit() def do_something(): """ Здесь мы только лишь пишем сообщение в Log, но можем реализовать абсолютно любые задачи выполняемые в фоне. """ while True: logger.info("this is an INFO message") time.sleep(5) if __name__ == "__main__": parser = argparse.ArgumentParser(description="Example daemon in Python") # Мы можем заменить default или запускать приложение с указанием нахождения # log файла, через параметр -l /путь_к_файлу/файл.log parser.add_argument('-l', '--log-file', default='/home/user/test_daemon.log') args = parser.parse_args() signal.signal(signal.SIGTERM, terminate) fh = logging.FileHandler(args.log_file) fh.setLevel(logging.INFO) fh.setFormatter(formatter) logger.addHandler(fh) do_something() 

Теперь при останове нашего демона:

systemctl start test_daemon 

Мы увидим в лог файле сообщение Recieved 15

2021-06-27 15:06:48,024 - test_daemon - INFO - this is an INFO message 2021-06-27 15:06:53,029 - test_daemon - INFO - this is an INFO message 2021-06-27 15:06:56,971 - test_daemon - INFO - Recieved 15 

Таким образом мы создали шаблон демона который в дальнейшем может быть использован для решения реальных фоновых задач.

Источник

Как запустить python скрипт на Linux в виде demon

Admin 16.10.2022 Linux, Python

Описание процесса от создания БД и до запуска скрипта.

Соединяемся со своим сервером и дальше работаем через консоль.

Переносим локальный проект на сервер

Создаем директорию для нашего нового приложения:

Клонируем свой git-проект на наш сервер:

Создаем виртуальное окружение python:

Создаем БД в PostgreSQL

Подключаемся к PostgreSQL:

CREATE DATABASE new-application TEMPLATE=template0 ENCODING ‘UTF-8’ LC_COLLATE ‘ru_RU.UTF-8’ LC_CTYPE ‘ru_RU.UTF-8’;

Назначаем привелегии новой таблице:

Выходим из postgres окружения:

В коде должно быть подключение к PostreSQL

Выдержка из примера подключения к PostreSQL вместе с логированием.

def create_connection (
db_name = ‘new-application’ ,
db_user = ‘ploshadka’ ,
db_password = ‘12345’ ,
db_host = ‘localhost’ ,
db_port = 5432
) :
connection = None
try :
connection = psycopg2. connect (
database = db_name ,
user = db_user ,
password = db_password ,
host = db_host ,
port = db_port ,
)
connection. autocommit = True
except psycopg2. OperationalError as error:
logger. info ( f ‘Ошибка: ‘ )
return connection

Создаем демон для запуска нашего скрипта на python

Внутри этого файла вставляем:

Description=New Application
After=network.target

[Service]
User=ploshadka
Group=www-data
WorkingDirectory=/home/ploshadka/new-application
Environment=»PATH=/home/ploshadka/new-application/venv/bin»
ExecStart=/home/ploshadka/new-application/venv/bin/python bot.py —start
ExecStop=/home/ploshadka/new-application/venv/bin/python bot.py —stop
ExecReload=/home/ploshadka/new-application/venv/bin/python bot.py —restart
TimeoutSec=30
Restart=always

Команды для запуска, остановки, перезагрузки службы

sudo systemctl start new-application
sudo systemctl stop new-application
sudo systemctl start new-application
sudo systemctl reload new-application

Читайте также

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

Источник

Оцените статью