Lazarus Dienst (LazDaemon) unter Linux installieren und steuern
- Winni
- Beiträge: 1577
- Registriert: Mo 2. Mär 2009, 16:45
- OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
- CPU-Target: 64Bit
- Wohnort: Fast Dänemark
Re: Lazarus Dienst (LazDaemon) unter Linux installieren und steuern
Hi!
Auch wenn Socke es schon gesagt hat:
Wichtig ist es erstmal den Service zu aktivieren mit
systemctl enable TestDaemon.services
Ohne das geht garnix. Danach klapt es auch mit start und stop des Service.
Winni
Auch wenn Socke es schon gesagt hat:
Wichtig ist es erstmal den Service zu aktivieren mit
systemctl enable TestDaemon.services
Ohne das geht garnix. Danach klapt es auch mit start und stop des Service.
Winni
-
- Lazarusforum e. V.
- Beiträge: 3178
- Registriert: Di 22. Jul 2008, 19:27
- OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
- CPU-Target: 32bit x86 armhf
- Wohnort: Köln
- Kontaktdaten:
Re: Lazarus Dienst (LazDaemon) unter Linux installieren und steuern
Ganz lustig wird es, wenn man mit Timer-Units arbeitet, weil man bestimmte Dinge zu bestimmten Uhrzeiten ausgeführt haben möchteWinni hat geschrieben: Mi 2. Feb 2022, 09:55 Ohne das geht garnix. Danach klapt es auch mit start und stop des Service.

MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
Re: Lazarus Dienst (LazDaemon) unter Linux installieren und steuern
Gott sei Dank ist das dann für den Dienst selber vermutlich "out of scope".
Armin.
-
- Lazarusforum e. V.
- Beiträge: 3178
- Registriert: Di 22. Jul 2008, 19:27
- OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
- CPU-Target: 32bit x86 armhf
- Wohnort: Köln
- Kontaktdaten:
Re: Lazarus Dienst (LazDaemon) unter Linux installieren und steuern
Für den Dienst selbst ist das nicht weiter relevant. Um die Systemd-Timer zu verstehen habe ich auch nur zwei Jahre gebrauchtNimral hat geschrieben: Mi 2. Feb 2022, 11:26 Gott sei Dank ist das dann für den Dienst selber vermutlich "out of scope".

Es hilft ungemein, sich die Dokumentation dazu nicht allzuweit weg zu legen und von Zeit zu Zeit mal einen Blick hinein zu werfen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
- willi4willi
- Lazarusforum e. V.
- Beiträge: 170
- Registriert: Sa 1. Nov 2008, 18:06
- OS, Lazarus, FPC: Lazarus 3.8 FPC 3.2.2 x86_64-win64-win32/win64 x86_64-linux-gtk2
- CPU-Target: i386, win64, arm
Re: Lazarus Dienst (LazDaemon) unter Linux installieren und steuern
Ich habe auch schon ewig herumgefummelt, ehe ich einen vernünftigen Dienst unter Linux hinbekommen habe.
Nachdem das alles nichts gebracht hatte, habe ich folgende Lösung. Ich nicht weiß nicht, ob es richtig ist, aber es funktioniert so schon viele Jahre einwandfrei.
Einfachste Variante ist ein Console-Programm, dass dann mit "kill" abgeschossen wird.
Das ist natürlich was ganz Schlimmes, so dass man das niemandem empfehlen kann. Aber da es funktioniert, mal hier mein Beispiel:
Das erzeugte Programm speicher ich unter /usr/local/bin/TestDaemon1 und erzeuge die Datei /etc/systemd/system/TestDaemon1.service:
Mit dem Kommando
aktiviere und
starte ich den Dienst.
Den Status kann ich mir mit
ansehen.
Oder, wenn wie in meinem Beispiel, der Dienst irgendwas ausgibt, dann sehe ich das live mit:
Natürlich sollte das Programm nicht so viel ausgeben, wie mein Beispiel. Sonst laufen vielleicht noch die Log-Dateien voll. 
Die oben beschriebene Methode ist deshalb so schlimm, weil der Dienst einfach mit kill getötet wird. Besser ist es, wenn man den Dienst von außen steuern kann, um es z.B. vernünftig zu beenden oder zu steuern.
Ich habe darum einen IPC-Server in das Programm integriert.
Hier mein Programmbeispiel:
Das erzeugte Programm speicher ich unter /usr/local/bin/TestDaemon2 und erzeuge die Datei /etc/systemd/system/TestDaemon2.service:
Dann wieder:
und
Möchte man den Dienst anhalten, dann kann man das mit
Und zum Weiterlaufen lassen:
Beendet wird der Dienst mit
und deinstalliert mit
Bleibt noch zu erwähnen, dass die eigene Funktion natürlich als Thread läuft, damit die Steuerung auch vernünftig reagiert.
Ich weiß, dass man einen Daemon normalerweise als Service-Applikation erstellt.
Aber das hat bei mir nur unter Windows geklappt. Unter Linux bin ich da nicht weitergekommen, deshalb habe ich diese Lösung gebastelt.
Und bei mir läuft diese auf etlichen Servern problemlos.
Vielleicht hilft es dir weiter?
Oder hat jemand ein Beispiel, wie man es besser macht?
Nachdem das alles nichts gebracht hatte, habe ich folgende Lösung. Ich nicht weiß nicht, ob es richtig ist, aber es funktioniert so schon viele Jahre einwandfrei.
Einfachste Variante ist ein Console-Programm, dass dann mit "kill" abgeschossen wird.
Das ist natürlich was ganz Schlimmes, so dass man das niemandem empfehlen kann. Aber da es funktioniert, mal hier mein Beispiel:
Code: Alles auswählen
program TestDaemon1;
{$mode objfpc}{$H+}
uses
Classes, SysUtils, CustApp;
type
TMyDaemon = class(TCustomApplication)
protected
procedure DoRun; override;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
end;
procedure TMyDaemon.DoRun;
begin
Writeln(FormatDatetime('dd.mm.yyyyThh:nn:ss,zzz',now()));
sleep(1000)
end;
constructor TMyDaemon.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
Writeln('Dienst gestartet');
end;
destructor TMyDaemon.Destroy;
begin
Writeln('Dienst beendet');
inherited Destroy;
end;
var
DaemonApplication: TMyDaemon;
{$R *.res}
begin
DaemonApplication:=TMyDaemon.Create(nil);
DaemonApplication.Run;
DaemonApplication.Free;
end.
Code: Alles auswählen
[Unit]
Description=MyDaemon
After=mysqld.service
[Service]
Type=simple
WorkingDirectory=/usr/local/bin
ExecStart=/usr/local/bin/TestDaemon1
ExecStop=/usr/bin/kill -9 $(pidof -s "/usr/local/bin/TestDaemon1")
[Install]
WantedBy=multi-user.target
Code: Alles auswählen
systemctl enable TestDaemon1.service
Code: Alles auswählen
systemctl start TestDaemon1.service
Den Status kann ich mir mit
Code: Alles auswählen
systemctl status TestDaemon1.service
Oder, wenn wie in meinem Beispiel, der Dienst irgendwas ausgibt, dann sehe ich das live mit:
Code: Alles auswählen
journalctl -f -u TestDaemon1.service

Die oben beschriebene Methode ist deshalb so schlimm, weil der Dienst einfach mit kill getötet wird. Besser ist es, wenn man den Dienst von außen steuern kann, um es z.B. vernünftig zu beenden oder zu steuern.
Ich habe darum einen IPC-Server in das Programm integriert.
Hier mein Programmbeispiel:
Code: Alles auswählen
program TestDaemon2;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils, CustApp,
crt, simpleipc;
type
{ TMyDaemon }
TMyDaemon = class(TCustomApplication)
protected
procedure DoRun; override;
private
FDaemonActive: boolean;
IPCClient: TSimpleIPCClient;
IPCServer: TSimpleIPCServer;
procedure ReceiveMessage(Sender: TObject);
procedure SendMessage(Command: String);
procedure SetDaemonActive(AValue: boolean);
procedure StartIPCServer;
procedure StopIPCServer;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
procedure MyService;
property DaemonActive:boolean read FDaemonActive write SetDaemonActive;
end;
procedure TMyDaemon.DoRun;
begin
if FDaemonActive then MyService; //< hier wird wirgendwas gemacht
if Assigned(IPCServer) then if IPCServer.Active then IPCServer.PeekMessage(0,true);
end;
procedure TMyDaemon.ReceiveMessage(Sender: TObject);
var Message :string;
begin
Message:=IPCServer.StringMessage;
Writeln('empfangen: ',Message);
case Message of
'-q' : Terminate;
'-r' : DaemonActive:=TRUE;
'-s' : DaemonActive:=FALSE;
{ weitere Steuerungsparameter möglich
... }
else
Writeln('unbekannt!')
end;
end;
procedure TMyDaemon.StartIPCServer;
begin
IPCServer:= TSimpleIPCServer.Create(nil);
try
writeln('Starte Daemon');
IPCServer.ServerID := Title;
IPCServer.Global := True;
IPCServer.OnMessage := @ReceiveMessage;
IPCServer.StartServer;
except
Writeln('Fehler!');
end;
end;
procedure TMyDaemon.StopIPCServer;
begin
if Assigned(IPCServer) then
begin
writeln('beende Daemon');
IPCServer.StopServer;
FreeAndNil(IPCServer);
end;
end;
procedure TMyDaemon.SendMessage(Command:String);
begin
IPCClient:= TSimpleIPCClient.Create(nil);
try
try
Writeln('Meldung zum Daemon');
IPCClient.ServerID := Title;
if IPCClient.ServerRunning
then
begin
IPCClient.Connect;
if IPCClient.Active
then IPCClient.SendStringMessage(Command)
else Writeln('Verbindung zum Daemon nicht möglich');
writeln(' gesendet: ',Command);
Command:='';
Writeln('Trenne Verbindung');
IPCClient.Disconnect;
end
else Writeln('keinen gestarteten Daemon gefunden!');
except
Writeln('ClientFehler!');
end;
finally
FreeAndNil(IPCClient);
Terminate;
end;
end;
procedure TMyDaemon.SetDaemonActive(AValue: boolean);
begin
if FDaemonActive=AValue then Exit;
if AValue
then Writeln('Mein Dienst aktiviert')
else Writeln('Mein Dienst unterbrochen');
FDaemonActive:=AValue;
end;
constructor TMyDaemon.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
FDaemonActive:=TRUE;
if ParamCount=1 then SendMessage(Paramstr(1)) else StartIPCServer ;
end;
destructor TMyDaemon.Destroy;
begin
StopIPCServer;
inherited Destroy;
end;
procedure TMyDaemon.MyService;
begin
{Nur zur Demonstration!! Besser ist ein Thread, der im Hintergrund was macht.}
Writeln(FormatDatetime('dd.mm.yyyyThh:nn:ss,zzz',now()));
sleep(1000)
end;
var
Application: TMyDaemon;
begin
Application:=TMyDaemon.Create(nil);
Application.Title:='MyDaemon';
Application.Run;
Application.Free;
end.
Code: Alles auswählen
[Unit]
Description=MyDaemon
After=mysqld.service
[Service]
Type=simple
WorkingDirectory=/usr/local/bin
ExecStart=/usr/local/bin/TestDaemon2
ExecStop=/usr/local/bin/TestDaemon2 -q
[Install]
WantedBy=multi-user.target
Code: Alles auswählen
systemctl enable TestDaemon2.service
systemctl start TestDaemon2.service
Code: Alles auswählen
systemctl status TestDaemon2.service
journalctl -f -u TestDaemon2.service
Code: Alles auswählen
/usr/local/bin/TestDaemon2 -s
Code: Alles auswählen
/usr/local/bin/TestDaemon2 -r
Code: Alles auswählen
systemctl stop TestDaemon2.service
Code: Alles auswählen
systemctl disable TestDaemon2.service
Ich weiß, dass man einen Daemon normalerweise als Service-Applikation erstellt.
Aber das hat bei mir nur unter Windows geklappt. Unter Linux bin ich da nicht weitergekommen, deshalb habe ich diese Lösung gebastelt.
Und bei mir läuft diese auf etlichen Servern problemlos.
Vielleicht hilft es dir weiter?
Oder hat jemand ein Beispiel, wie man es besser macht?
Viele Grüße
Willi4Willi
------------
-
- Lazarusforum e. V.
- Beiträge: 3178
- Registriert: Di 22. Jul 2008, 19:27
- OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
- CPU-Target: 32bit x86 armhf
- Wohnort: Köln
- Kontaktdaten:
Re: Lazarus Dienst (LazDaemon) unter Linux installieren und steuern
Was spricht denn dagegen auf SIGTERM oder SIGINT zu reagieren? Man muss ja nicht gleich den Prozess abwürgen, nur weil man ihn beenden will.willi4willi hat geschrieben: Mi 2. Feb 2022, 16:01 Die oben beschriebene Methode ist deshalb so schlimm, weil der Dienst einfach mit kill getötet wird. Besser ist es, wenn man den Dienst von außen steuern kann, um es z.B. vernünftig zu beenden oder zu steuern.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
- Winni
- Beiträge: 1577
- Registriert: Mo 2. Mär 2009, 16:45
- OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
- CPU-Target: 64Bit
- Wohnort: Fast Dänemark
Re: Lazarus Dienst (LazDaemon) unter Linux installieren und steuern
Hi !
SIGHUP wird bei demons gerne genutzt, um diesen neu zu starten. z.B. mit veränderter Conf-Datei. Oder bei geänderter System-Umgebung.
Ist auch sehr hilfreich während der Entwicklung.
Winni
SIGHUP wird bei demons gerne genutzt, um diesen neu zu starten. z.B. mit veränderter Conf-Datei. Oder bei geänderter System-Umgebung.
Ist auch sehr hilfreich während der Entwicklung.
Winni
Re: Lazarus Dienst (LazDaemon) unter Linux installieren und steuern
Gibt es dafür eigentlich irgendeine Anleitung?Socke hat geschrieben: Di 1. Feb 2022, 15:51 Ein Package kann -dUseCThreads für alle Projekte setzen, in denen es eingebunden wird. Wenn der Daemon das macht, sollte dessen Paket den Parameter setzen.
Ich habe gerade folgendes probiert:
- ein Package gebaut, und darin unter "Compiler Options" - "Custom Options" zwei eingetragen:
Code: Alles auswählen
-dGlobalFlag
-dGlobalFlag1
Code: Alles auswählen
function GetFlagState: string;
begin
Result := '';
{$IFDEF GlobalFlag}
Result := 'Unit2: GlobalFlag is set';
{$ELSE}
Result := 'Unit2: GlobalFlag is not set';
{$ENDIF}
{$IFDEF GlobalFlag1}
Result := Result + ' GlobalFlag1 is set';
{$ELSE}
Result := Result + ' GlobalFlag1 is not set';
{$ENDIF}
end;
Code: Alles auswählen
program project1;
uses Unit1, Unit2;
begin
writeln(Unit1.GetFlagState());
writeln(Unit2.GetFlagState());
readln;
end.
Das Resultat ist gleich null:
Code: Alles auswählen
Unit1: GlobalFlag is not set GlobalFlag1 is not set
Unit2: GlobalFlag is not set GlobalFlag1 is not set
Armin
-
- Beiträge: 607
- Registriert: Di 19. Mai 2015, 20:05
- OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
- CPU-Target: x86_64-linux-gtk2
Re: Lazarus Dienst (LazDaemon) unter Linux installieren und steuern
Hallo Armin,
hast du das schon gelesen https://wiki-lazarus-freepascal-org.tra ... _tr_pto=sc?
Obwohl ich da auch nicht durchblicke möchte ich dir kurz mitteilen was/wie's bei mir unter Linux Mint geht.
Ich habe einmal einen Flag hier gesetzt: Hinzufügen, Benutzerdefinierte Option Und zwei mal hier: Wenn ich bei der Abfrage bei newflag3 windows eingebe muss ich ab und zu zweimal ok drücken bis es erkannt wird.
Mein Code sieht so aus:
Viele Grüße
Bernd
hast du das schon gelesen https://wiki-lazarus-freepascal-org.tra ... _tr_pto=sc?
Obwohl ich da auch nicht durchblicke möchte ich dir kurz mitteilen was/wie's bei mir unter Linux Mint geht.
Ich habe einmal einen Flag hier gesetzt: Hinzufügen, Benutzerdefinierte Option Und zwei mal hier: Wenn ich bei der Abfrage bei newflag3 windows eingebe muss ich ab und zu zweimal ok drücken bis es erkannt wird.
Mein Code sieht so aus:
Code: Alles auswählen
{$IFDEF NewFlag1}
showmessage('newflag1 gesetzt');
{$ELSE}
showmessage('newflag1 nicht gesetzt');
{$ENDIF}
{$IFDEF NewFlag2}
showmessage('newflag2 gesetzt');
{$ELSE}
showmessage('newflag2 nicht gesetzt');
{$ENDIF}
{$IFDEF NewFlag3}
showmessage('newflag3 gesetzt');
{$ELSE}
showmessage('newflag3 nicht gesetzt');
{$ENDIF}
Bernd
- Dateianhänge
-
project1.zip
- (105.83 KiB) 156-mal heruntergeladen
Re: Lazarus Dienst (LazDaemon) unter Linux installieren und steuern
Jep, den kannte ich schon.
Ich glaube, Du musst den Ausgangspunkt der Diskussion sehen. Es ging um den $IFDEF UseCThreads, den Lazarus per Default in jede neue Projektdatei setzt, und die Frage, wer wann und wo UseCThreads denn setzen würde.
Meine Idee war, das (meiner Meinung nach) nutzlose Konstrukt komplett rauszuwerfen. Wir waren uns aber unsicher, ob es nicht vielleicht von einem Package, z.B. lazDaemon gesetzt werden könnte. Nach meinen Tests: nein, wohl eher nicht. Aber eventuell weist mir Deine Idee einen anderen Weg, muss das mit den Custom Options gleich mal mit einem Package probieren.
Ich glaube, Du musst den Ausgangspunkt der Diskussion sehen. Es ging um den $IFDEF UseCThreads, den Lazarus per Default in jede neue Projektdatei setzt, und die Frage, wer wann und wo UseCThreads denn setzen würde.
Meine Idee war, das (meiner Meinung nach) nutzlose Konstrukt komplett rauszuwerfen. Wir waren uns aber unsicher, ob es nicht vielleicht von einem Package, z.B. lazDaemon gesetzt werden könnte. Nach meinen Tests: nein, wohl eher nicht. Aber eventuell weist mir Deine Idee einen anderen Weg, muss das mit den Custom Options gleich mal mit einem Package probieren.