Wie kann man ein Java-Programm dämonisieren?


73

Ich habe ein Java-Programm, das ich auf einem Linux-System dämonisieren möchte. Mit anderen Worten, ich möchte es in einer Shell ausführen und nach dem Abmelden weiter ausführen lassen. Ich möchte auch in der Lage sein, das Programm sauber zu stoppen.

Ich habe diesen Artikel gefunden, der eine Kombination aus Shell-Scripting und Java-Code verwendet, um den Trick auszuführen. Es sieht gut aus, aber ich möchte, wenn möglich, etwas Einfacheres.

Was ist Ihre bevorzugte Methode, um ein Java-Programm auf einem Linux-System zu dämonisieren?



9
Versuchen Sie es nohup java prog &.
Ceving

Eine sauberere Möglichkeit, Dienste unter UNIX zu verwalten cr.yp.to/daemontools.html
Velu

Antworten:



32

Wenn Sie sich nicht auf den an anderer Stelle genannten Java Service Wrapper verlassen können (z. B. wenn Sie Ubuntu ausführen, das keine gepackte Version von SW enthält), möchten Sie dies wahrscheinlich auf die altmodische Weise tun: Lassen Sie Ihr Programm seine PID in / schreiben var / run / $ schedame.pid und schreiben Sie ein Standard-SysV-Init-Skript (verwenden Sie beispielsweise das für ntpd als Beispiel, es ist einfach). Machen Sie es vorzugsweise auch LSB-konform.

Im Wesentlichen testet die Startfunktion, ob das Programm bereits ausgeführt wird (indem getestet wird, ob /var/run/$progname.pid vorhanden ist und der Inhalt dieser Datei die PID eines laufenden Prozesses ist) und ob es nicht ausgeführt wird

logfile=/var/log/$progname.log
pidfile=/var/run/$progname.pid
nohup java -Dpidfile=$pidfile $jopts $mainClass </dev/null > $logfile 2>&1

Die Stoppfunktion überprüft /var/run/$progname.pid, prüft, ob diese Datei die PID eines laufenden Prozesses ist, und überprüft, ob es sich um eine Java-VM handelt (um einen Prozess nicht zu beenden, der die PID einfach von einem Toten wiederverwendet hat Instanz meines Java-Daemons) und beendet dann diesen Prozess.

Beim Aufruf beginnt meine main () -Methode damit, ihre PID in die in System.getProperty ("pidfile") definierte Datei zu schreiben.

Eine große Hürde: In Java gibt es keine einfache und standardmäßige Methode, um die PID des Prozesses zu ermitteln, in dem die JVM ausgeführt wird.

Folgendes habe ich mir ausgedacht:

private static String getPid() {
    File proc_self = new File("/proc/self");
    if(proc_self.exists()) try {
        return proc_self.getCanonicalFile().getName();
    }
    catch(Exception e) {
        /// Continue on fall-back
    }
    File bash = new File("/bin/bash");
    if(bash.exists()) {
        ProcessBuilder pb = new ProcessBuilder("/bin/bash","-c","echo $PPID");
        try {
            Process p = pb.start();
            BufferedReader rd = new BufferedReader(new InputStreamReader(p.getInputStream()));
            return rd.readLine();
        }
        catch(IOException e) {
            return String.valueOf(Thread.currentThread().getId());
        }
    }
    // This is a cop-out to return something when we don't have BASH
    return String.valueOf(Thread.currentThread().getId());
}

9
Java muss die PID nicht schreiben, das Skript kann dies auch (echo $!> /Var/run/my.pid). Da normalerweise nur root in / var / run schreiben kann, können Sie das Shell-Skript verwenden wird als root ausgeführt und der Daemon wird als anderer Benutzer ausgeführt.
David Rabinowitz

Außer, dass Sie uid oder euid in Java nicht ändern können, also müssen Sie es von der Shell aus mit sudo tun ... es ist ein bisschen schmerzhaft, wenn Sie mich fragen. Es ist einfacher, / var / run und var / log für den Benutzer beschreibbar zu machen, als ...
Varkhan

3
Der Grund dafür, dass Java die PID-Datei / Sperrdatei schreibt, besteht darin, zu wissen, ob die Initialisierungsphase des Daemons erfolgreich abgeschlossen wurde (indem am Ende dieser Phase geschrieben wird).
Varkhan

Diese Antwort ist nutzlos. Sie möchten die Gabelung ausführen, nachdem die Sockel erstellt wurden. Dies löst nur den Prozess von der Shell, es ist eine ganz andere Sache.
LtWorf

Die Copout-Option funktioniert nicht - die Thread-ID stimmt mit ziemlicher Sicherheit nicht mit der Prozess-ID überein.
Luke Hutchison

24

Ich schreibe häufig Skripte oder Befehlszeilen, die im Wesentlichen so aussehen, wenn ich möchte:

  1. Führen Sie ein Programm aus, das gegen Seufzer immun ist
  2. Das ist völlig getrennt von der Shell, die es erzeugt, und
  3. Erzeugt eine Protokolldatei aus stderr und stdout, deren Inhalt ebenfalls angezeigt wird, aber
  4. Ermöglicht es mir, die Anzeige des laufenden Protokolls zu beenden und andere Aufgaben auszuführen, ohne den laufenden Prozess zu stören

Genießen.

nohup java com.me.MyProgram </dev/null 2>&1 | tee logfile.log &

1
Sie können es mit cron und der @ reboot-Funktion starten.
Sven

15

Ich bevorzuge den Befehl nohup . Der Blog-Beitrag sagt, dass es bessere Möglichkeiten gibt, aber ich denke nicht, dass sie besser genug sind.


Es ist nicht vollständig dämonisierend. Was ist, wenn das Betriebssystem neu gestartet wird? Hier ist die sauberere Lösung mit daemontools stackoverflow.com/a/35569052/1840774
Velu

1
Dadurch wird der Dienst nicht aufgerufen, sobald das System ausfällt oder neu gestartet wird!
Velu


4

Das hängt davon ab. Wenn es nur eine einmalige Sache ist, möchte ich sie dämonisieren und dann nach Hause gehen, aber normalerweise warte ich auf die Ergebnisse.

nohup java com.me.MyProgram &

an der Kommandozeile. Um es sauber zu töten, haben Sie viele Möglichkeiten. Möglicherweise haben Sie einen Listener für SIGKILL oder überprüfen einen Port und fahren herunter, wenn eine Verbindung hergestellt wird. Überprüfen Sie regelmäßig eine Datei. Differenzansätze haben unterschiedliche Schwächen. Wenn es für die Produktion verwendet werden soll, würde ich mir mehr Gedanken darüber machen und wahrscheinlich ein Skript in /etc/init.d werfen, das es nicht aktualisiert, und ein ausgefeilteres Herunterfahren durchführen, wie z. B. das, was Tomcat hat.


Ja, es ist nicht vollständig dämonisierend. Was ist, wenn das Betriebssystem neu gestartet wird? Hier ist die sauberere Lösung mit daemontools stackoverflow.com/a/35569052/1840774
Velu

4

Meine bevorzugte Methode unter Ubuntu ist die Verwendung des libslack-Dienstprogramms 'daemon'. Dies ist, was Jenkins unter Ubuntu verwendet (woher ich die Idee hatte). Ich habe es für meine Jetty-basierten Serveranwendungen verwendet und es funktioniert gut.

Wenn Sie den Daemon-Prozess stoppen, signalisiert dies der JVM das Herunterfahren. Sie können den Code zum Herunterfahren / Bereinigen an dieser Stelle ausführen, indem Sie einen Shutdown-Hook bei Runtime.addShutdownHook () registrieren.


2

Bei dieser Frage geht es darum, ein beliebiges Programm (nicht Java-spezifisch) zu dämonisieren, sodass einige der Antworten möglicherweise auf Ihren Fall zutreffen:


2

DaemonTools: - Eine sauberere Methode zum Verwalten von Diensten unter UNIX https://cr.yp.to/daemontools.html

  1. Installieren Sie Daemon-Tools über die URL https://cr.yp.to/daemontools/install.html. Befolgen Sie die dort genannten Anweisungen. Bei Problemen versuchen Sie bitte die Anweisungen https://gist.github.com/rizkyabdilah/8516303

  2. Erstellen Sie eine Datei unter /etc/init/svscan.conf und fügen Sie die folgenden Zeilen hinzu (nur für cent-os-6.7 erforderlich).

 start on runlevel [12345]
 stop on runlevel [^12345]
 respawn
 exec /command/svscanboot
  1. Erstellen Sie ein neues Skript mit dem Namen run in / service / vm / folder und fügen Sie die folgenden Zeilen hinzu.
#!/bin/bash    
echo starting VM 
exec java -jar
/root/learning-/daemon-java/vm.jar

Hinweis: Ersetzen Sie das Glas durch Ihre eigene Glasdatei. oder eine beliebige Java-Klassendatei.

  1. Starten Sie das System neu

  2. svstat / service / vm sollte jetzt betriebsbereit sein!

  3. svc -d / service / vm sollte vm jetzt runter bringen!
  4. svc -u / service / vm sollte vm jetzt aufrufen!

0
nohup java -jar {{your-jar.jar}} > /dev/null &

Dies kann den Trick tun.


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.