Scripte als Deamon laufen lassen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

Ich habe nur mal ein paar Fragen zum Thema, Pythonprogramme im Hintergrund laufen lassen.

unter Linux etc. kann ich ja mit einem `&` ein Script in den Hintergrund verschieben. Was mache ich dagegen unter Windows (macos sollte auch mit `&` klappen oda?)?

Weiterhin: Wie "nutze" ich diesen "Hintergrundmodus". Es geht darum, das ich mir ein kleines Script machen möchte, was mir zu bestimmten Zeiten mit der Hilfe einiger kleiner Tools einige meiner Lieblingsshows meines Lieblingssenders aufnehmen möchte und die entsprechenden Shows mit einem einfachen Timestamp versehen (als Dateinamen).

Ich würde denken, das mein Script einfach in einer `while` Schleife die Zeit nach und nach wieder überprüft. Nur... wie würden dann Sachen wie `überprüfe alle 5 sekunden` auf die entsprechende Zeit. (weil so genau muss es ja nun nicht sein).

Freue mich über sämtliche Referenzen/Tipps, die ihr dazu habt.

MfG EnTeQuAk
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ich handel das mal in Nummern ab:

1. Es heisst nich Deamon sondern Daemon
2. Mit & erstellst du keinen Daemon
3. Ja, zwei Forks müssen sein ;-)
4. Google ist da schnell: http://aspn.activestate.com/ASPN/Cookbo ... ipe/278731
5. Für Windows-Services hatte Gerold hier mal ein Beispiel geschrieben: http://www.python-forum.de/viewtopic.ph ... 2e7f08cf01
6. Eine while das auf das Vergehen von Zeit wartet ist immer grausam, verwende doch einfach "threading.Timer"

So geht das viel schneller als mit langen Texten :D
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

EnTeQuAk hat geschrieben:Freue mich über sämtliche Referenzen/Tipps, die ihr dazu habt.
cron?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
sunmountain
User
Beiträge: 89
Registriert: Montag 13. März 2006, 17:18

EyDu hat geschrieben: 3. Ja, zwei Forks müssen sein ;-)
Warum ?

Code: Alles auswählen

import os
import time
import sys

pid = os.fork()
if pid>0:
    sys.exit(0)
os.chdir('/')
os.setsid()
while True:
    print '.',
    time.sleep(5)
Wobei das ein schlechtes Beispiel ist, da das print weiter auf die aufrufende Konsole schreibt. Richtiger wäre ein schließen der Handels
sys.stdin,sys.stderr und sys.stdout gewesen.
Ich wüßte keinen technischen Grund für den 2. fork.
Das wiederspricht auch den manpages dazu.

"
System Calls fork(2)

NAME
fork, fork1 - create a new process

SYNOPSIS
#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);

pid_t fork1(void);

DESCRIPTION
The fork() and fork1() functions create a new process. The
new process (child process) is an exact copy of the calling
process (parent process). The child process inherits the
following attributes from the parent process:
"
...
"
RETURN VALUES
Upon successful completion, fork() and fork1() return 0 to
the child process and return the process ID of the child
process to the parent process. Otherwise, (pid_t)-1 is
returned to the parent process, no child process is created,
and errno is set to indicate the error.
"
2x forken bedeutet: erzeuge Kind, erzeuge Enkel und schließe Vater und Kind. Merkwürdig.

Ich überlege gerade, ob das hier http://ezine.daemonnews.org/200603/mgp00004.png in Python umzusetzen, also die "Serviceseparation", nicht BGP natürlich ;-)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

sunmountain hat geschrieben:Warum ?
Wenn du weiter als Benutzer am System angemeldet bleibst der den Daemon gestartet hat sollte es keine Probleme geben, nur wenn du dich abmeldest beenden einige Unixe bei nur einem Fork den Prozess, bei zweien bis du auf der sicheren Seite.
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Das ist aber unsauber. Dann lieber nohup benutzen oder selbst SIGHUP abfangen.
Benutzeravatar
sunmountain
User
Beiträge: 89
Registriert: Montag 13. März 2006, 17:18

EyDu hat geschrieben: Wenn du weiter als Benutzer am System angemeldet bleibst der den Daemon gestartet hat sollte es keine Probleme geben, nur wenn du dich abmeldest beenden einige Unixe bei nur einem Fork den Prozess, bei zweien bis du auf der sicheren Seite.
Genau das glaube ich nicht.
Definition Daemon: kein kontrollierendes TTY.
Sobald der fork() erfolgreich war, ist diese Bedingung erfüllt.
Deswegen ein ? in der Spalte bei top oder ps.
Da kein TTY auch kein Beenden.
Ansonsen hätte ich jahrelang was falsch gemacht und die POSIX Doku
wäre für die Tonne.
Rebecca hat geschrieben:Das ist aber unsauber. Dann lieber nohup benutzen oder selbst SIGHUP abfangen.
Nohup ist genau für den Fall gedacht:

nohup programm &

Also Daemon für "Arme", da das TTY noch da ist, bekommen alle
Prozesse beim Verlassen der Session in Kette das SIGHUP.

*Das* ist unsauber.
lunar

sunmountain hat geschrieben:
EyDu hat geschrieben: Wenn du weiter als Benutzer am System angemeldet bleibst der den Daemon gestartet hat sollte es keine Probleme geben, nur wenn du dich abmeldest beenden einige Unixe bei nur einem Fork den Prozess, bei zweien bis du auf der sicheren Seite.
Genau das glaube ich nicht.
Definition Daemon: kein kontrollierendes TTY.
Genau deswegen erzeugt der erste fork ja noch keinen Daemon. Der Kindprozess hat zwar kein kontrollierendes Terminal mehr, ist aber immer noch Session Leader, kann also ein Terminal öffnen. Erst der zweite fork() führt dazu, dass der Enkel-Prozess niemals ein kontrollierendes Terminal haben wird.

Außerdem ist der zweite fork() nötig, um den "Enkel"-Prozess verwaisen zu lassen. Dadurch übernimmt init direkt die Kontrolle über diesen Prozess. Das vermeidet ewig laufende, nicht zu killende Zombieprozesse.

Edit: Mmmh, ich dachte immer, der doppelte fork() sei notwendig und üblich. Tatsächlich hab ich das in diverse Quellen nicht finden können: openssh, hald und smbd forken alle nur einmal. Der zweite fork kommt erst indirekt durch die Verwendung von start-stop-daemon hinzu...

Das scheinen die Meinungen auseinander zu gehen (siehe auch die Kommentare des Snippets im Codebook in EyDu's Posting).
Benutzeravatar
sunmountain
User
Beiträge: 89
Registriert: Montag 13. März 2006, 17:18

lunar hat geschrieben: Genau deswegen erzeugt der erste fork ja noch keinen Daemon. Der Kindprozess hat zwar kein kontrollierendes Terminal mehr, ist aber immer noch Session Leader, kann also ein Terminal öffnen. Erst der zweite fork() führt dazu, dass der Enkel-Prozess niemals ein kontrollierendes Terminal haben wird.
Und genau dafür gibt es setsid():

SETSID(2) OpenBSD Programmer's Manual SETSID(2)

NAME
setsid - create session and set process group ID

SYNOPSIS
#include <unistd.h>

pid_t
setsid(void);

DESCRIPTION
The setsid function creates a new session. The calling process is the
session leader of the new session, is the process group leader of a new
process group and has no controlling terminal.
The calling process is
the only process in either the session or the process group.

Upon successful completion, the setsid function returns the value of the
process group ID of the new process group, which is the same as the pro-
cess ID of the calling process.
Benutzeravatar
sunmountain
User
Beiträge: 89
Registriert: Montag 13. März 2006, 17:18

Code: Alles auswählen

import os
import sys

def daemonize(pidfile='/tmp/daemon.pid'):
    os.chdir('/')
    (sys.stdin,sys.stdout,sys.stderr) = [ open('/dev/null',m) for m in ('r','a','a')]
    pid = os.fork()
    if pid:
        f = open(pidfile,'w')
        print >>f,pid
        f.close()
        sys.exit(0)
    os.setsid()
    os.umask(0)
Ich hoffe das kann jemand gebrauchen ;-)
So mache ich das normlerweise (habe in es so in Perl gemacht).

Example:
bash-2.05# ./daemonize.py
bash-2.05# cat /tmp/daemon.pid
13605
bash-2.05# ps -ef |grep 13605
root 13605 1 0 08:00:11 ? 0:00 /opt/ASpy23/bin/python ./daemonize.py
bash-2.05# kill `cat /tmp/daemon.pid`
bash-2.05# ps -ef |grep 13605

Also nix Zombie etc.
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

yey!

Danke sunmountain!

Danke auch an alle anderen! Ich muss nun erstmal mein Scriptchen basteln.

Dein `deamonize` ist dabei sicherlich hilfreich.


MfG EnTeQuAk
lunar

sunmountain hat geschrieben:
lunar hat geschrieben: Genau deswegen erzeugt der erste fork ja noch keinen Daemon. Der Kindprozess hat zwar kein kontrollierendes Terminal mehr, ist aber immer noch Session Leader, kann also ein Terminal öffnen. Erst der zweite fork() führt dazu, dass der Enkel-Prozess niemals ein kontrollierendes Terminal haben wird.
Und genau dafür gibt es setsid()
Ja und? Nichts anderes habe ich geschrieben. Das Problem ist scheinbar, dass ein Session Leader Prozess immer noch ein kontrollierendes Terminal kriegen kann, wenn er einen fd öffnet, welcher auf ein Terminal zeigt. So zumindest liest man es. Allerdings scheint das nicht für alle Unixe zu gelten.
Benutzeravatar
sunmountain
User
Beiträge: 89
Registriert: Montag 13. März 2006, 17:18

lunar hat geschrieben: Ja und? Nichts anderes habe ich geschrieben. Das Problem ist scheinbar, dass ein Session Leader Prozess immer noch ein kontrollierendes Terminal kriegen kann, wenn er einen fd öffnet, welcher auf ein Terminal zeigt.
Das ist dann aber weder das Problem von fork() noch von setsid() sondern einzig "Schlamperei".
Deswegen sollen ja auch stdin(-err,-out) auf /dev/null gesetzt werden.
Alles andere ist seit Dekaden in den POSIX Dokumenten festgeschrieben
und ich kenne *kein einziges* UNIX/UNIX-Derivat/Linux bei dem das so
wäre.
Der meiste C code um fork() und setsid() ist bei den meisten Projekten
mit auffallend wenig #ifdef's geschmückt.

Siehe auch: http://en.wikipedia.org/wiki/Process_group

Es ist einfach absolut essentiell, die Entkopplung vom tty hinzukriegen.
Ansonsten wäre es faktisch nicht möglich (ohne riesige Verrenkungen) einen Daemon zu schreiben- man denke nur an einen über ein virtuelles tty (ssh session) gestarteten Daemon.

Man muss fork() und setsid() einfach als Duo betrachten.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

sunmountain hat geschrieben:Das ist dann aber weder das Problem von fork() noch von setsid() sondern einzig "Schlamperei".
Das mag es in einigen Fällen durch aus sein, aber trotzdem soll die Software auch auf diesen Kisten laufen und die Anpassung ist einfach minimal. Ich möchte mal sehen, wie du einem Kunden erklärst, dass er sein vielleicht schon jahrelang laufendes Unix für deine Software austauschen soll, nur weil du du solche kleinen Ausnahmen nicht beachtest.


--- This post is "optimized" for Firefox 2.0 ;-) ---
Benutzeravatar
sunmountain
User
Beiträge: 89
Registriert: Montag 13. März 2006, 17:18

EyDu hat geschrieben:Ich möchte mal sehen, wie du einem Kunden erklärst, dass er sein vielleicht schon jahrelang laufendes Unix für deine Software austauschen soll, nur weil du du solche kleinen Ausnahmen nicht beachtest.
Ich will ja nicht nörgeln: Beispiele bitte.
Ich habe echt Schwierigkeiten mir das vorzustellen; ich würde das gerne
reproduzieren.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

sunmountain hat geschrieben:Ich will ja nicht nörgeln: Beispiele bitte.
Verstehe ich dich richtig, dass du ein Beispiel möchtest, dass ein Kunde sein vorhandenen System behalten will, oder Vorgaben für bestimmte Komponenten eines Systems macht?
Benutzeravatar
sunmountain
User
Beiträge: 89
Registriert: Montag 13. März 2006, 17:18

EyDu hat geschrieben:Verstehe ich dich richtig, dass du ein Beispiel möchtest, dass ein Kunde sein vorhandenen System behalten will, oder Vorgaben für bestimmte Komponenten eines Systems macht?
Nein, das kenne ich nur zu gut ...
ich möchte gerne Beispiele haben, bei denen 2 forks zwingend notendig
sind, oder mal ein Programmfragment sehen, was zu der Nichtaufgabe
des kontrollierenden tty's führt.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

sunmountain hat geschrieben:Nein, das kenne ich nur zu gut ...
Ja ja, was wäre das Leben schön ohne Kunden... :D
sunmountain hat geschrieben:ich möchte gerne Beispiele haben, bei denen 2 forks zwingend notendig
Ehrlich gesagt ist mir auch noch kein Unix untergekommen, bei dem ich dieses Problem gehabt hätte (wobei auch wirklich wenig damit mache). Nach der Menge an Threads im Netz (wobei 100%-ige Sicherheit wohl hier auch nichg gegeben ist) in denen es um den double-fork geht, scheint es diese Distributionen wirklich zu geben oder zumindest gegeben zu haben. Und mit diesen paar zusätzlichen Zeilen ist man zumindest immer auf der sicheren Seite. Es ist ja nun auch nicht so, dass man sich jeden Tag ein deamonize-Modul schreibt. Dieser Thread hat wohl schon mehr Zeit in Anspruch genommen, als jenes Modul zu basteln, welches im Moment für diese Aufgabe verwende :)
lunar

Im Bezug auf C ist diese Diskussion ja eigentlich sowieso sinnlos, weil es ja die "daemon" Funktion in der glibc gibt ;)
Antworten