Run python init d

Как сделать Python script запущенным как сервис или демон в Linux

Я написал Python script, который проверяет определенный адрес электронной почты и передает новые электронные письма во внешнюю программу. Как я могу заставить этот script выполнять 24/7, например, превратить его в демон или службу в Linux. Нужен ли мне цикл, который никогда не заканчивается в программе, или это можно сделать, просто повторив код повторно несколько раз?

У вас есть два варианта здесь.

  1. Сделайте правильную работу cron, которая вызывает ваш скрипт. Cron – это общее имя для демона GNU/Linux, который периодически запускает сценарии в соответствии с заданным вами расписанием. Вы добавляете свой скрипт в crontab или помещаете символическую ссылку на него в специальный каталог, и демон выполняет его запуск в фоновом режиме. Вы можете прочитать больше в Википедии. Существует множество различных демонов cron, но в вашей системе GNU/Linux она должна быть уже установлена.
  2. Используйте некоторый подход к Python (например, библиотеку), чтобы ваш скрипт мог демонизировать себя. Да, это потребует простой циклы событий (где ваши события запускаются по таймеру, возможно, обеспечивается функцией сна).

Я бы не рекомендовал вам выбирать 2., потому что вы на самом деле повторяете функциональность cron. Системная парадигма Linux – позволить нескольким простым инструментам взаимодействовать и решать ваши проблемы. Если нет дополнительных причин, по которым вы должны создавать демона (помимо периодического запуска), выберите другой подход.

Также, если вы используете daemonize с циклом и происходит сбой, никто не будет проверять почту после этого (как указал Иван Невоструев в комментариях к этому ответу). Хотя, если скрипт добавлен как задание cron, он просто сработает снова.

Читайте также:  Темная тема html css

Здесь хороший класс, который взят из здесь:

#!/usr/bin/env python import sys, os, time, atexit from signal import SIGTERM class Daemon: """ A generic daemon class. Usage: subclass the Daemon class and override the run() method """ def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): self.stdin = stdin self.stdout = stdout self.stderr = stderr self.pidfile = pidfile def daemonize(self): """ do the UNIX double-fork magic, see Stevens' "Advanced Programming in the UNIX Environment" for details (ISBN 0201563177) http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 """ try: pid = os.fork() if pid > 0: # exit first parent sys.exit(0) except OSError, e: sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(1) # decouple from parent environment os.chdir("/") os.setsid() os.umask(0) # do second fork try: pid = os.fork() if pid > 0: # exit from second parent sys.exit(0) except OSError, e: sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(1) # redirect standard file descriptors sys.stdout.flush() sys.stderr.flush() si = file(self.stdin, 'r') so = file(self.stdout, 'a+') se = file(self.stderr, 'a+', 0) os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) # write pidfile atexit.register(self.delpid) pid = str(os.getpid()) file(self.pidfile,'w+').write("%s\n" % pid) def delpid(self): os.remove(self.pidfile) def start(self): """ Start the daemon """ # Check for a pidfile to see if the daemon already runs try: pf = file(self.pidfile,'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if pid: message = "pidfile %s already exist. Daemon already running?\n" sys.stderr.write(message % self.pidfile) sys.exit(1) # Start the daemon self.daemonize() self.run() def stop(self): """ Stop the daemon """ # Get the pid from the pidfile try: pf = file(self.pidfile,'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if not pid: message = "pidfile %s does not exist. Daemon not running?\n" sys.stderr.write(message % self.pidfile) return # not an error in a restart # Try killing the daemon process try: while 1: os.kill(pid, SIGTERM) time.sleep(0.1) except OSError, err: err = str(err) if err.find("No such process") > 0: if os.path.exists(self.pidfile): os.remove(self.pidfile) else: print str(err) sys.exit(1) def restart(self): """ Restart the daemon """ self.stop() self.start() def run(self): """ You should override this method when you subclass Daemon. It will be called after the process has been daemonized by start() or restart(). """ 

Вы должны использовать библиотеку python-daemon, она заботится обо всем.

Читайте также:  Python class nested class

Из PyPI: Library для реализации хорошо зарекомендовавшего себя процесса демона Unix.

Вы можете использовать fork(), чтобы отсоединить ваш script от tty и продолжить его, например:

import os, sys fpid = os.fork() if fpid!=0: # Running as daemon now. PID is fpid sys.exit(0) 

Конечно, вам также нужно реализовать бесконечный цикл, например

while 1: do_your_check() sleep(5) 

Вы также можете запустить python script как службу с помощью оболочки script. Сначала создайте оболочку script для запуска python script, как это (имя файла сценария)

#!/bin/sh script='/home/.. full path to script' /usr/bin/python $script & 

теперь создайте файл в /etc/init.d/scriptname

#! /bin/sh PATH=/bin:/usr/bin:/sbin:/usr/sbin DAEMON=/home/.. path to shell script scriptname created to run python script PIDFILE=/var/run/scriptname.pid test -x $DAEMON || exit 0 . /lib/lsb/init-functions case "$1" in start) log_daemon_msg "Starting feedparser" start_daemon -p $PIDFILE $DAEMON log_end_msg $? ;; stop) log_daemon_msg "Stopping feedparser" killproc -p $PIDFILE $DAEMON PID=`ps x |grep feed | head -1 | awk ''` kill -9 $PID log_end_msg $? ;; force-reload|restart) $0 stop $0 start ;; status) status_of_proc -p $PIDFILE $DAEMON atd && exit 0 || exit $? ;; *) echo "Usage: /etc/init.d/atd " exit 1 ;; esac exit 0 

Теперь вы можете запустить и остановить ваш python script с помощью команды /etc/init.d/scriptname start или stop.

cron – отличный выбор для многих целей. Однако он не создает службу или демон, как вы просили в OP. cron просто запускает задания периодически (это означает, что задание запускается и останавливается) и не чаще, чем раз в минуту. Существуют проблемы с cron – например, если предыдущий экземпляр вашего script все еще работает при следующем расписании cron и запускает новый экземпляр, это нормально? cron не обрабатывает зависимости; он просто пытается начать работу, когда расписание говорит.

Если вы обнаружите ситуацию, когда вам действительно нужен демон (процесс, который никогда не перестает работать), взгляните на supervisord . Он предоставляет простой способ обернуть нормальную, не-daemonized script или программу и заставить ее работать как демон. Это намного лучший способ, чем создание собственного демона Python.

Простая и поддерживаемая версия – это Deamonize Install it from Python Package Index (PyPI):

. import os, sys from daemonize import Daemonize . def main() # your code here if __name__ == '__main__': myname=os.path.basename(sys.argv[0]) pidfile='/tmp/%s' % myname # any name daemon = Daemonize(app=myname,pid=pidfile, action=main) daemon.start() 

как использовать команду $nohup в linux?

Я использую его для запуска моих команд на моем сервере Bluehost.

Прошу совета, если я ошибаюсь.

Сначала прочитайте псевдонимы почты. Почтовый псевдоним будет делать это в почтовой системе, если вам не придется обманывать демонов или сервисов или что-то в этом роде.

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

Если вы действительно хотите написать ненужный сложный сервер, вы можете сделать это.

Это все, что нужно. Ваш script просто петли и спит.

import time def do_the_work(): # one round of polling -- checking email, whatever. while True: time.sleep( 600 ) # 10 min. try: do_the_work() except: pass 

Если вы используете терминал (ssh или что-то еще), и вы хотите сохранить долговременную работу script после выхода из терминала, вы можете попробовать следующее:

создать виртуальный терминал внутри (а именно abc): screen -dmS abc

теперь мы подключаемся к abc: screen -r abc

Итак, теперь мы можем запустить python script: python Keep_sending_mail.py

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

Так как этот Keep_sending_mail.py PID принадлежит виртуальному экрану, а не Терминал (SSH)

Если вы хотите вернуться, проверьте состояние работы script, вы можете снова использовать screen -r abc

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

Я бы рекомендовал это решение. Вам нужно наследовать и переопределить метод run .

import sys import os from signal import SIGTERM from abc import ABCMeta, abstractmethod class Daemon(object): __metaclass__ = ABCMeta def __init__(self, pidfile): self._pidfile = pidfile @abstractmethod def run(self): pass def _daemonize(self): # decouple threads pid = os.fork() # stop first thread if pid > 0: sys.exit(0) # write pid into a pidfile with open(self._pidfile, 'w') as f: print >> f, os.getpid() def start(self): # if daemon is started throw an error if os.path.exists(self._pidfile): raise Exception("Daemon is already started") # create and switch to daemon thread self._daemonize() # run the body of the daemon self.run() def stop(self): # check the pidfile existing if os.path.exists(self._pidfile): # read pid from the file with open(self._pidfile, 'r') as f: pid = int(f.read().strip()) # remove the pidfile os.remove(self._pidfile) # kill daemon os.kill(pid, SIGTERM) else: raise Exception("Daemon is not started") def restart(self): self.stop() self.start() 

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

чтобы создать что-то, что работает как сервис, вы можете использовать эту вещь:

Первое, что вам нужно сделать, это установить Cement framework:
Работа с рамкой Цемента – это работа кадра CLI, на которую вы можете развернуть свое приложение.

интерфейс командной строки приложения:

 from cement.core.foundation import CementApp from cement.core.controller import CementBaseController, expose from YourApp import yourApp class Meta: label = 'base' description = "your application description" arguments = [ (['-r' , '--run'], dict(action='store_true', help='Run your application')), (['-v', '--version'], dict(action='version', version="Your app version")), ] (['-s', '--stop'], dict(action='store_true', help="Stop your application")), ] @expose(hide=True) def default(self): if self.app.pargs.run: #Start to running the your app from there ! YourApp.yourApp() if self.app.pargs.stop: #Stop your application YourApp.yourApp.stop() class App(CementApp): class Meta: label = 'Uptime' base_controller = 'base' handlers = [MyBaseController] with App() as app: app.run() 
 import threading class yourApp: def __init__: self.loger = log_exception.exception_loger() thread = threading.Thread(target=self.start, args=()) thread.daemon = True thread.start() def start(self): #Do every thing you want pass def stop(self): #Do some things to stop your application 

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

Чтобы запустить приложение, просто выполните это в командной строке

Источник

Using init.d script to start my python program on startup

I have a python script that I would like to be run at startup. I have made a init.d script as follows:

#! /bin/sh case "$1" in start) echo "starting pitracker" su 'pi' -c 'python3 /home/pi/python/main/myprogram.py&' ;; stop) echo "stopping" ;; esac exit 0 

I have changed the permission of this startup script to 755. I have also created a symbolic link using

update-rc.d /etc/init.d/dnscheck defaults 
File "/home/pi/python/main/myprogram.py" , line 21, in import RPi.GPIO as GOPI RunTimeError: No access to /dev/mem. Try running as root! 

And when I change the username in my startup script to ‘root’, nothing happens at all. I believe this is a permission problem for accessing the GPIO. How can I start up my script without running into this issue?

3 Answers 3

There is no need for the su as the init.d scripts run as root. In general any command in init should have a full path to the executable.

Incidentally it would probably be easier to edit /etc/rc.local

Okay, I’m just starting down the init.d path myself, so don’t consider this an authoritative answer. But I think you need to include an LSB Header along these lines (your mileage may vary):

#! /bin/sh # ### BEGIN INIT INFO # Provides: pitracker # Required-Start: $all # Required-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Track pi. # Description: This service is used to track a pi. ### END INIT INFO 

The Required-Start: and Required-Stop: lines make sure that certain system resources are up and running before it tries to start your program. I think — but I’m not sure — that the message you’re seeing is because the system hasn’t yet set up /dev/mem when it tries to launch your app.

Источник

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