Seite 1 von 1

Scripte als Deamon laufen lassen

Verfasst: Montag 7. Mai 2007, 19:04
von EnTeQuAk
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

Verfasst: Montag 7. Mai 2007, 19:11
von EyDu
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

Re: Scripte als Deamon laufen lassen

Verfasst: Montag 7. Mai 2007, 19:21
von Leonidas
EnTeQuAk hat geschrieben:Freue mich über sämtliche Referenzen/Tipps, die ihr dazu habt.
cron?

Verfasst: Dienstag 8. Mai 2007, 07:02
von sunmountain
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 ;-)

Verfasst: Dienstag 8. Mai 2007, 08:24
von EyDu
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.

Verfasst: Dienstag 8. Mai 2007, 09:14
von Rebecca
Das ist aber unsauber. Dann lieber nohup benutzen oder selbst SIGHUP abfangen.

Verfasst: Dienstag 8. Mai 2007, 09:44
von sunmountain
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.

Verfasst: Dienstag 8. Mai 2007, 11:01
von 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).

Verfasst: Mittwoch 9. Mai 2007, 06:40
von sunmountain
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.

Final words ;-)

Verfasst: Mittwoch 9. Mai 2007, 07:02
von sunmountain

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.

Verfasst: Mittwoch 9. Mai 2007, 07:07
von EnTeQuAk
yey!

Danke sunmountain!

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

Dein `deamonize` ist dabei sicherlich hilfreich.


MfG EnTeQuAk

Verfasst: Mittwoch 9. Mai 2007, 12:37
von 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.

Verfasst: Mittwoch 9. Mai 2007, 14:57
von sunmountain
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.

Verfasst: Mittwoch 9. Mai 2007, 15:53
von EyDu
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 ;-) ---

Verfasst: Mittwoch 9. Mai 2007, 20:15
von sunmountain
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.

Verfasst: Mittwoch 9. Mai 2007, 20:37
von EyDu
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?

Verfasst: Mittwoch 9. Mai 2007, 20:52
von sunmountain
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.

Verfasst: Freitag 11. Mai 2007, 22:03
von EyDu
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 :)

Verfasst: Samstag 12. Mai 2007, 12:17
von lunar
Im Bezug auf C ist diese Diskussion ja eigentlich sowieso sinnlos, weil es ja die "daemon" Funktion in der glibc gibt ;)