Problem bei "shutdown restart" / Anpassung Exit Code

Begonnen von vbs, 05 Dezember 2015, 18:51:49

Vorheriges Thema - Nächstes Thema

vbs

Ich sitze gerade dran, FHEM bei mir als systemd-Dienst laufen zu lassen.  Und zwar hab ich FHEM als "forking" konfiguriert und geben das PID-File von FHEM beim systemd an. systemd bietet ja auch eine Prozessüberwachung und kann dann FHEM neu starten im Falle eines Absturzes.

Das sieht dann im Moment so aus:
[Service]
Type=forking
User=fhem
Restart=on-failure
PermissionsStartOnly=true
PIDFile=/var/run/fhem/fhem.pid
WorkingDirectory=/media/fhem
ExecStartPre=-/bin/mkdir /var/run/fhem
ExecStartPre=/bin/chown -R fhem /var/run/fhem
ExecStart=/usr/bin/perl fhem.pl fhem-vbs.cfg


Das klappt soweit auch alles ganz gut. Ich kann starten und beenden und auch wenn ich FHEM mit SIGKILL abschieße, wird es sauber von systemd neu gestartet. Das Problem ist aber nun das Verhalten bei "shutdown restart": Wenn ich das eingebe, verschwindet der FHEM-Prozess und es wird kein neuer gestartet (weder von FHEM selbst, noch von systemd).

Ich vermute, dass es daran liegt, dass der User "fhem" als welcher der FHEM-Prozess läuft, bei mir keine zugeordnete Shell hat (brauchen ja Daemon-User normalerweise nicht). Aber FHEM ruft dann bei "shutdown restart" auf:
system("(sleep " . AttrVal("global", "restartDelay", 2) .
                                 "; exec $^X $0 $attr{global}{configfile})&");
exit(0);


Aus Sicht von systemd wiederum, hat sich der FHEM-Prozess sauber mit ExitCode 0 beendet. Also kein Grund zum Neustart.

Sind also eigentlich zwei Probleme:
- Zum einen denke ich, dass der momentane Neustart-Mechanismus von FHEM nicht mit einem shell-losen Benutzer klar kommt
- Zum anderen die saubere Einbindung in init-Dienste wie zB systemd

Hat schon jemand eine Lösung für sowas?

Solche Sachen sind ja recht OS/Distributions-spezifisch. Eine Möglichkeit wäre mMn, diese Restart-Logik aus FHEM auszulagern. Zum Beispiel könnte man ein Attribut machen, dass bewirkt, dass sich FHEM im Falle von "shutdown restart" nicht selbst neu startet, sondern sich einfach nur beendet. Jedoch dann nicht mit Exit Code 0, sondern etwas ungleich 0, was dann der Prozessüberwachung einen gewünschten Neustartet signalisiert. Bei einem normalen "shutdown" ändert sich nichts: Einfach beenden mit ExitCode 0.

Ich würde mich natürlich auch anbieten, sowas einzbauen. Würde aber erstmal gerne abklären, ob es dafür schon andere Lösungen/Ideen gibt.

rudolfkoenig

define myShutdown cmdalias shutdown restart AS { exit(1) }

vbs

Ok, so kann mans auch machen. Reicht aber für mich aus, danke!

ok

Bei mir läuft seit 1-2 Monaten folgendes UNIT-File ohne Probleme (auf eines RasPi mit jessie):

[Unit]
Description=FHEM Perl Server
After=syslog.target network.target

[Service]
Type=oneshot
RemainAfterExit=yes
User=fhem
Group=fhem
WorkingDirectory=/opt/fhem
ExecStart=/usr/bin/perl /opt/fhem/fhem.pl /opt/fhem/fhem.cfg
ExecStop=/usr/bin/perl /opt/fhem/fhem.pl 7072 shutdown
ExecReload=/usr/bin/perl /opt/fhem/fhem.pl 7072 shutdown;/usr/bin/perl /opt/fhem/fhem.pl /opt/fhem/fhem.cfg;

[Install]
WantedBy=multi-user.target


vbs

Der springende Punkt ist ja der automatische Neustart von FHEM. Das ist in deinem Script nicht drin, oder?

vbs

Kann es sein, dass bei der vorgeschlagenen Methode beim Aufruf von exit(1) keine state-Files und co. mehr geschrieben werden? Ich hab das Gefühl, dass seitdem ich das mit der Methode mache, mein state beim Restart irgendwie nicht mehr derselbe ist wie vorher :(
Es wird doch der gesamte FHEM-Shutdown-Vorgang übersprungen, der bei einem "echten" Shutdown durchlaufen wird, oder?

sub
CommandShutdown($$)
{
  my ($cl, $param) = @_;
  return "Usage: shutdown [restart]"
        if($param && $param ne "restart");

  DoTrigger("global", "SHUTDOWN", 1);
  Log 0, "Server shutdown";

  foreach my $d (sort keys %defs) {
    CallFn($d, "ShutdownFn", $defs{$d});
  }

  WriteStatefile();
  unlink($attr{global}{pidfilename}) if($attr{global}{pidfilename});
  if($param && $param eq "restart") {
    if ($^O !~ m/Win/) {
      system("(sleep " . AttrVal("global", "restartDelay", 2) .
                                 "; exec $^X $0 $attr{global}{configfile})&");
    } elsif ($winService->{AsAService}) {
      # use the OS SCM to stop and start the service
      exec('cmd.exe /C net stop fhem & net start fhem');
    }
  }
  exit(0);
}

rudolfkoenig

exit() macht genau das, und nicht mehr.
Ich habe shutdown mit dem optionalen exit Wert erweitert, Syntax waere:
Zitatshutdown 1

vbs


Ralli

Zitat von: rudolfkoenig am 05 Dezember 2015, 19:16:07
define myShutdown cmdalias shutdown restart AS { exit(1) }

Ich hole das Thema noch einmal hoch. Ja, ich weiß, es gibt zwischenzeitlich unzählige Threads zu dem Thema "shutdown restart systemd". Und ich habe viele, viele gelesen. Meines Erachtens ist das grundsätzliche Problem aber nicht gelöst.

Nutze ich den cmdalias, funktioniert sowohl ein in fhem durchgeführter shutdown als auch ein shutdown restart, wenn ich in fhem.service restart=on-failure definiert habe. Der einzige Nachteil ist der, dass innerhalb von fhem nicht die Shutdown-Funktion aufgerufen wird sondern direkt ein exit durchgeführt wird - damit ist bspw. auch kein Log des Shutdowns protokolliert.

Wäre es nicht eine Möglichkeit, über ein optionales Attribut in global den Exitcode für den Restart extra definieren zu können und den in der Shutdown-Funktion dann mitzugeben?
Gruß,
Ralli

Proxmox 8.2 Cluster mit HP ED800G2i7, Intel NUC11TNHi7+NUC7i5BNH, virtualisiertes fhem 6.3 dev, virtualisierte RaspberryMatic (3.75.7.20240420) mit HB-RF-ETH 1.3.0 / RPI-RF-MOD, HM-LAN-GW (1.1.5) und HMW-GW, FRITZBOX 7490 (07.57), FBDECT, Siri und Alexa

rudolfkoenig

https://fhem.de/commandref_modular.html#shutdown:

Zitatshutdown [restart|exitValue]

Shut down the server (after saving the state information ). It triggers the global:SHUTDOWN event. If the optional restart parameter is specified, FHEM tries to restart itself. exitValue may be important for start scripts.

Example:

    shutdown
    shutdown restart
    shutdown 1

Ralli

#10
Hallo Rudi,

ja, ich weiß (durch das CmdAlias-Beispiel) - "shutdown 1" macht genau das, was in diesem Kontext erwartet wird. Fhem wird ordentlich beendet, Ausstieg mit Exitcode 1, über systemd wird neu gestartet. So mache ich es auch bei mir.

Aber halt nicht über das "schönere" Kommando "shutdown restart".

Ist nur Optik, nicht Funktionalität. "Schön" wäre, man könnte restart mit einem Exitcode belegen :-).

Edit:
Was natürlich auch geht, ist das von dir verwandte Beispiel abzuwandeln:


define myShutdown cmdalias shutdown restart AS shutdown 1 }
Gruß,
Ralli

Proxmox 8.2 Cluster mit HP ED800G2i7, Intel NUC11TNHi7+NUC7i5BNH, virtualisiertes fhem 6.3 dev, virtualisierte RaspberryMatic (3.75.7.20240420) mit HB-RF-ETH 1.3.0 / RPI-RF-MOD, HM-LAN-GW (1.1.5) und HMW-GW, FRITZBOX 7490 (07.57), FBDECT, Siri und Alexa

rudolfkoenig

Mit restart=on-failure und exit 1 bei shutdown restart wird FHEM zweimal gestartet (oder ich uebersehe etwas).

Vor dem Loesungsvorschlag will ich das Problem verstehen.

Ralli

Nein, kann ich nicht bestätigen.

Ich habe zwei Ubuntu-Systeme mit systemd. Bei beiden beendet fhem grundsätzlich bei einem "shutdown" mit exitcode 0 und bei einem "shutdown restart" genau so.

Mit den Standard-Einstellungen in fhem.service ("restart=always") wird fhem durch systemd immer neu gestartet, egal ob in fhem ein "shutdown" oder ein "shutdown restart" veranlasst wurde. Mit der Einstellung "restart=on-abnormal" oder auch "restart=on-failure" in fhem.service wird fhem bei einem "shutdown" und auch bei "shutdown restart" beendet, vom systemd jedoch nicht neu gestartet, weil der exitcode immer 0 ist. Erst dann, wenn als exitcode nicht 0 übergeben wird, startet systemd bei der Einstellung "restart=on-failure" den fhem-Prozess neu.

Lange Rede, kurzer Sinn, mit anderen Worten: wenn ich aus fhem heraus einen shutdown ohne Restart veranlassen möchte, darf in fhem.service nicht "restart=always" definiert sein. Wennn ich aus fhem heraus aber die Möglichkeit belassen möchte, nicht nur einen shutdown sondern auch einen restart von fhem zu veranlassen, muss ich für systemd über den exitcode unterscheiden.
Gruß,
Ralli

Proxmox 8.2 Cluster mit HP ED800G2i7, Intel NUC11TNHi7+NUC7i5BNH, virtualisiertes fhem 6.3 dev, virtualisierte RaspberryMatic (3.75.7.20240420) mit HB-RF-ETH 1.3.0 / RPI-RF-MOD, HM-LAN-GW (1.1.5) und HMW-GW, FRITZBOX 7490 (07.57), FBDECT, Siri und Alexa

rudolfkoenig

Genau so habe ich es auch verstanden.
Bei der systemd Einstellung restart=on-failure fuehrt shutdown zu einem normalen shutdown, und shutdown 1 zu einem restart.
Wenn man das FHEM restart unbedingt mit dem Befehl "shutdown restart" ausloesen will, dann muss man
define myShutdown cmdalias shutdown restart AS shutdown 1
definieren. Soe wie Du es gezeigt hast, bloss ohne }

Alternativ verwendet man die Systemd Voreinstellung restart=no und man muss in FHEM auch nichts umstellen.

vbs

Zitat von: rudolfkoenig am 25 April 2020, 18:44:04
Alternativ verwendet man die Systemd Voreinstellung restart=no und man muss in FHEM auch nichts umstellen.
Anzumerken, dass in diesem Fall FHEM auch im Falle eines Crashes nicht neu gestartet wird. Da muss man dann händisch tätig werden.