Kiedy piszę demona python, wychwytuję wszystkie wyjątki i wrzucam do pliku dziennika. Używam nie tylko do debugowania, ale także podczas produkcji. Mam mały skrypt, który uruchamiam każdego ranka i który szuka czegoś niepokojącego w logach.
Oczywiście pomaga również w utrzymaniu działania demona.
Trochę przykładowego kodu (usuwam nieciekawe części):
import logging
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO,
format='%(asctime)s %(levelname)s %(message)s',
filename=LOG_FILE,
filemode='w')
logging.info("Sincrod inicializado")
if not DEBUG:
daemonize()
while True:
try:
actua()
except:
logging.error(sys.exc_info())
if (datetime.datetime.now().hour > NOITE_EMPEZA\
and datetime.datetime.now().hour < NOITE_REMATA):
time.sleep(INTERVALO_NOITE)
else:
time.sleep(INTERVALO_DIA)
Gdzie actua () jest prawdziwym demonem (pisze też, aby się zalogować). Zauważ, że mam również zmienną DEBUG w pliku ustawień, gdy jest to prawda, nie rozwidlam demona, więc jest uruchamiany na konsoli.
Demony
Demony są uniksowym odpowiednikiem usług Windows. Są to procesy działające w tle niezależnie od innych procesów. Oznacza to, że ich ojciec jest zwykle inicjowany i że są oderwani od jakiegokolwiek tty. Ponieważ są one niezależne, nie ma z góry określonego miejsca na umieszczenie ich wyników.
Istnieje wiele bibliotek i fragmentów Pythona do stworzenia demona, w powyższym przykładzie używam własnej funkcji, która łączy kilka pomysłów z wersji Steinar Knutsens i Jeff Kunces. To jest tak proste, jak to możliwe, pamiętaj, że rozwidlam dwa razy .
def daemonize():
"""Forks this process creating a daemon and killing the original one"""
if (not os.fork()):
# get our own session and fixup std[in,out,err]
os.setsid()
sys.stdin.close()
sys.stdout = NullDevice()
sys.stderr = NullDevice()
if (not os.fork()):
# hang around till adopted by init
ppid = os.getppid()
while (ppid != 1):
time.sleep(0.5)
ppid = os.getppid()
else:
# time for child to die
os._exit(0)
else:
# wait for child to die and then bail
os.wait()
sys.exit()