AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Eigener Dienst beendet nicht korrekt...

Offene Frage von "cherry"
Ein Thema von cherry · begonnen am 15. Jan 2009 · letzter Beitrag vom 30. Apr 2009
Antwort Antwort
Seite 3 von 4     123 4      
Benutzerbild von cherry
cherry

Registriert seit: 14. Nov 2005
561 Beiträge
 
RAD-Studio 2009 Ent
 
#21

Re: Eigener Dienst beendet nicht korrekt...

  Alt 27. Apr 2009, 11:15
Leider funktioniert die Geschichte immer noch nicht 100% ig...

Zitat von Angel4585:
ich würde die nicht auf true setzen.

meine Dienste sehen idR so aus:

Delphi-Quellcode:
procedure TMyDienst.Execute;
begin
while not terminated do
  begin
  //Irgendwas machen
  ServiceThread.ProcessRequests(False);
  end;
end;
kann es sein, dass wenn das "//irgendwas machen" etwas lange dauert, dass der Dienst dann die Message (shutdown) zu spät erhält und desshalb nicht richtig beendet?

wenn ja, was kann ich dagegen tun?

es kann schon mal sein, dass der Dienst irgendwelche scans durchführt oder in die DB schreibt und mehr als 20-30 sekunden daran arbeitet...
Ist das nur mein Gefühl, oder ist die ganze Welt verrückt geworden!?
  Mit Zitat antworten Zitat
Angel4585

Registriert seit: 4. Okt 2005
Ort: i.d.N.v. Freiburg im Breisgau
2.199 Beiträge
 
Delphi 2010 Professional
 
#22

Re: Eigener Dienst beendet nicht korrekt...

  Alt 27. Apr 2009, 12:13
klar es wird das ausgeführt was du schreibst.
Wenn du dem Sienst sagst er soll das alles ausführen und zwischendurch nich zum beenden prüfen dauerts ne weile...
versuch mal den Teil auszulassen um zu schauen obs generell funktioniert
Martin Weber
Ich bin ein Rüsselmops
  Mit Zitat antworten Zitat
Benutzerbild von cherry
cherry

Registriert seit: 14. Nov 2005
561 Beiträge
 
RAD-Studio 2009 Ent
 
#23

Re: Eigener Dienst beendet nicht korrekt...

  Alt 27. Apr 2009, 12:26
Zitat von Angel4585:
versuch mal den Teil auszulassen um zu schauen obs generell funktioniert
hmm... genau wie ichs vermutet habe...

Delphi-Quellcode:
while not terminated do
begin
  ServiceThread.ProcessRequests(False);
  Sleep(500); // halbe sek. warten
end;
funktioniert einwandfrei... beendet immer korrekt
aaaaber:

Delphi-Quellcode:
while not terminated do
begin
  ServiceThread.ProcessRequests(False);
  Sleep(15000); // 15 sek. warten
end;
beendet nie korrekt...
Das bedeutet: Mein Dienst beendet korrekt, wenn er im gegebenen Zeitraum (von windows festgelegtes timeout) "ServiceThread.ProcessRequests" passiert, ansonsten schmiert er sozusagen ab!

Nun jetzt wissen wir wo das Problem ist...
aber wie löse ich das nun...

Ich will ja die Aktionen noch beenden bevor der dienst sich verabschiedet... kann ich nicht sagen: Hey, du olles System warte gefälligst bis mein dienst korrekt heruntergefahren wurde...
Ist das nur mein Gefühl, oder ist die ganze Welt verrückt geworden!?
  Mit Zitat antworten Zitat
nahpets
(Gast)

n/a Beiträge
 
#24

Re: Eigener Dienst beendet nicht korrekt...

  Alt 27. Apr 2009, 14:06
Hallo,

das was Du da beschreibst sieht mir schwer nach Timeoutproblemen aus.

Kläre bitte zuerst, was Dein Dienst alles an "Fremdem" benötigt. Versuche dann in der Dienstekonfiguration diese Abhängigkeiten zu berücksichtigen, damit Dein Dienst vor den anderen, benötigten Diensten runtergefahren wird. Laufen Datenbank... auf dem gleichen Rechner als Dienste? Dann musst Du die Reihenfolge beim Starten und Beenden berücksichtigen.
Ist der Dienst abhängig von anderen Programmen, die nicht als Dienst laufen, dann dürfte es schwierig werden, die Abhängigkeiten in den Griff zu bekommen.

Wenn Dein Dienst mal 20-30 Sekunden "irgendwas" macht und dazwischen der Rechner runter gefahren wird bzw. der Dienst gestoppt wird, bist Du vermutlich in Bezug auf Timeoutzeiten jenseits von Gut und Böse. Kannst Du die langen "Arbeitsschleifen" irgendwie ohne Datenverlust auf kleiner Happen verteilen?

Ein Dienst hat ja diverse Ereignisse, Start, Stop, Pause, Shutdown ... . Kannst Du Dir dort irgendwie ein globales Flag setzen, auf das Deine Langläuferroutinen ggfls. reagieren, um ihre Arbeit abzubrechen?

Was macht der Dienst, wenn er für 20-30 Sekunen "On Tour" ist. Wird das timerabhängig gesteuert. Hätten kürzere Timerintervalle auch kürzere Bearbeitungszeiten zur Folge. Dann wäre ggfls. ein "mach öfter weniger" eine Lösungsansatz.

Damit das Betriebssystem merkt, ob Dein Dienst läuft, muss der auf jeden Fall reagieren und darf nicht "beliebig" lange vor sich hin wurschteln. Zugegeben weiß ich momentan keine Antwort auf die Frage: "Hey, du..."
  Mit Zitat antworten Zitat
Benutzerbild von cherry
cherry

Registriert seit: 14. Nov 2005
561 Beiträge
 
RAD-Studio 2009 Ent
 
#25

Re: Eigener Dienst beendet nicht korrekt...

  Alt 30. Apr 2009, 09:09
Zitat von nahpets:
Hallo,
Kläre bitte zuerst, was Dein Dienst alles an "Fremdem" benötigt. Versuche dann in der Dienstekonfiguration diese Abhängigkeiten zu berücksichtigen, damit Dein Dienst vor den anderen, benötigten Diensten runtergefahren wird. Laufen Datenbank... auf dem gleichen Rechner als Dienste? Dann musst Du die Reihenfolge beim Starten und Beenden berücksichtigen. Ist der Dienst abhängig von anderen Programmen, die nicht als Dienst laufen, dann dürfte es schwierig werden, die Abhängigkeiten in den Griff zu bekommen.
Mein Dienst benötigt keine Fremdprogramme und keine anderen Dienste, naja, ausser dass ich per ADO auf einen SQL-Server (nicht auf meinem Computer) zugreiffe.
Braucht ADO da noch was ?

Zitat von nahpets:
Wenn Dein Dienst mal 20-30 Sekunden "irgendwas" macht und dazwischen der Rechner runter gefahren wird bzw. der Dienst gestoppt wird, bist Du vermutlich in Bezug auf Timeoutzeiten jenseits von Gut und Böse. Kannst Du die langen "Arbeitsschleifen" irgendwie ohne Datenverlust auf kleiner Happen verteilen?
Das wird sehr schwierig. Da das was etwas länger gehen könnte eine for- schleife ist die in die Datenbank schreibt...

Zitat von nahpets:
Ein Dienst hat ja diverse Ereignisse, Start, Stop, Pause, Shutdown ... . Kannst Du Dir dort irgendwie ein globales Flag setzen, auf das Deine Langläuferroutinen ggfls. reagieren, um ihre Arbeit abzubrechen?
Ich wüsste nicht wie ich das anstellen sollte. soll ich denn in meiner OnExecute Procedure immer wieder nach diesem flag fragen und allenfalls exiten?
das wäre doch kein schöner code;

Zitat von nahpets:
Was macht der Dienst, wenn er für 20-30 Sekunen "On Tour" ist. Wird das timerabhängig gesteuert. Hätten kürzere Timerintervalle auch kürzere Bearbeitungszeiten zur Folge. Dann wäre ggfls. ein "mach öfter weniger" eine Lösungsansatz.
Da das was etwas länger gehen könnte eine for- schleife ist die in die Datenbank schreibt...

Zitat von nahpets:
Damit das Betriebssystem merkt, ob Dein Dienst läuft, muss der auf jeden Fall reagieren und darf nicht "beliebig" lange vor sich hin wurschteln. Zugegeben weiß ich momentan keine Antwort auf die Frage: "Hey, du..."
Und wenn ich in meinem On execute nichts stehen hätte als folgendes:

Delphi-Quellcode:
while not terminated do
begin
  if dienststoppen then
  begin
    TerminateThread(...);
    TerminateThread(...);
    TerminateThread(...);
  end;
  ServiceThread.ProcessRequests(False);
  Sleep(500); // halbe sek. warten
end;
und dann alle aktionen in eigenen threads? ware das eine Idee?

Wie habt ihr das bei euren diensten gemacht? habt ihr da immer nur kleine Aktionen drin die nie länger dauern als 10 sek?
Ich bin am verzweifeln... heul
Ist das nur mein Gefühl, oder ist die ganze Welt verrückt geworden!?
  Mit Zitat antworten Zitat
nahpets
(Gast)

n/a Beiträge
 
#26

Re: Eigener Dienst beendet nicht korrekt...

  Alt 30. Apr 2009, 10:04
Hallo,

mit dem Abbruch der For-Schleife hatte ich mir in dieser Form vorgestellt:
Delphi-Quellcode:
unit SVReplikationUnit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs,
  DB, ADODB, ExtCtrls, Registry, StrUtils;

type
  TReplikator = class(TService)
    tm: TSpecialTimer;
    acABC: TADOConnection;
    acBN: TADOConnection;
    qryBN: TADOQuery;
    qryABC: TADOQuery;
    qryBNMaxUhrzeit: TADOQuery;
    qryABCMaxUhrzeit: TADOQuery;
    procedure ServiceCreate(Sender: TObject);
    procedure ServiceExecute(Sender: TService);
    procedure tmTimer(Sender: TObject);
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServicePause(Sender: TService; var Paused: Boolean);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
    procedure ServiceContinue(Sender: TService; var Continued: Boolean);
    procedure ServiceShutdown(Sender: TService);
    procedure ServiceBeforeInstall(Sender: TService);
    procedure ServiceAfterUninstall(Sender: TService);
  private
    { Private-Deklarationen }
  public
    function GetServiceController: TServiceController; override;
    { Public-Deklarationen }
    bShutDownOrStopOrPause : Boolean;
  end;

var
  TReplikatorReplikator: TReplikator;

implementation

{$R *.DFM}

procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  TReplikatorReplikator.Controller(CtrlCode);
end;

function TReplikator.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;

procedure TReplikator.ServiceCreate(Sender: TObject);
begin
  // ShortDateFormat := 'yyyy-mm-dd'; // Darf nicht gesetzt werden, da auch die Datenbankinhalte übersetzt werden.
  ThousandSeparator := ','; // Muss gesetzt werden, da die Datenbank Komma erwartet.
  DecimalSeparator := '.'; // Muss gesetzt werden, da die Datenbank Punkt erwartet.
  bShutDownOrStopOrPause := False;
end;

procedure TReplikator.ServiceExecute(Sender: TService);
begin
  while not Terminated do ServiceThread.ProcessRequests(True);
end;

procedure TReplikator.tmTimer(Sender: TObject);
Var
          i : Integer;
begin
  tm.Enabled := False;
  // Hier passiert so allerhand, was auch 'ne Weile dauern kann.
  For i := 0 to MaxInt do begin
    // Ist der Abbruchschalter gesetzt, dann aufhören.
    // if i Mod 100 = 0 then // wenn nicht bei jedem Schleifendurchlauf geprüft werden soll.
    if bShutDownOrStopOrPause then Break;
  end;
  tm.Enabled := True;
end;

procedure TReplikator.ServiceStart(Sender: TService; var Started: Boolean);
Var
          iOffset : Integer;
begin
  tm.Enabled := True;
  bShutDownOrStopOrPause := False;
end;

procedure TReplikator.ServicePause(Sender: TService; var Paused: Boolean);
begin
  tm.Enabled := False;
  bShutDownOrStopOrPause := True;
end;

procedure TReplikator.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  tm.Enabled := False;
  bShutDownOrStopOrPause := True;
end;

procedure TReplikator.ServiceContinue(Sender: TService; var Continued: Boolean);
Var
          iOffset : Integer;
begin
  tm.Enabled := True;
  bShutDownOrStopOrPause := False;
end;

procedure TReplikator.ServiceShutdown(Sender: TService);
begin
  tm.Enabled := False;
  bShutDownOrStopOrPause := True;
end;

// Messagefile registrieren
procedure TReplikator.ServiceBeforeInstall(Sender: TService);
Var
    Reg : TRegistry;
begin
  Reg := TRegistry.Create;
  Reg.RootKey := HKEY_LOCAL_MACHINE;
  Reg.OpenKey('system\CurrentControlSet\Services\EventLog\Application\' + Self.Name,True);
  Reg.WriteString('EventMessageFile',ParamStr(0));
  Reg.WriteInteger('TypesSupported',7);
  Reg.CloseKey;
  Reg.OpenKey('system\CurrentControlSet\Services\TReplikator\' + Self.Name,True);
  Reg.WriteString('Description','Repliziert die Daten zwischen den Datenbanken ABC und BN');
  Reg.CloseKey;
  Reg.Free;
end;

// Messagefile aus Registrierung entfernen
procedure TReplikator.ServiceAfterUninstall(Sender: TService);
Var
    Reg : TRegistry;
begin
  Reg := TRegistry.Create;
  Reg.RootKey := HKEY_LOCAL_MACHINE;
  Reg.DeleteKey('system\CurrentControlSet\Services\EventLog\Application\' + Self.Name);
  Reg.DeleteKey('system\CurrentControlSet\Services\TReplikatorReplikator\' + Self.Name);
  Reg.CloseKey;
  Reg.Free;
end;

end.
Das ist nicht getestet, sondern nur schnell aus einem vorhandenen Service zusammengedaddelt. Hoffe trotzdem, dass es Dir bei der Problemlösung weiterhilft.
  Mit Zitat antworten Zitat
Benutzerbild von cherry
cherry

Registriert seit: 14. Nov 2005
561 Beiträge
 
RAD-Studio 2009 Ent
 
#27

Re: Eigener Dienst beendet nicht korrekt...

  Alt 30. Apr 2009, 10:17
hmmm...

du hast im service execute eigentlich nicht viel drin, du regelst alles mit einem timer. Ist das die bessere lösung im allgemeinen.
Denn so wird ja wenigstens immer wieder ServiceThread.ProcessRequests(True); abgefragt..

und bei dir steht da auch true, also er soll auf eine message warten...
vielleicht müsste ich meinen dienst mal mit timer realisieren?!
Ist das nur mein Gefühl, oder ist die ganze Welt verrückt geworden!?
  Mit Zitat antworten Zitat
nahpets
(Gast)

n/a Beiträge
 
#28

Re: Eigener Dienst beendet nicht korrekt...

  Alt 30. Apr 2009, 10:34
Hallo,
Zitat von cherry:
hmmm...

du hast im service execute eigentlich nicht viel drin, du regelst alles mit einem timer. Ist das die bessere lösung im allgemeinen.
Denn so wird ja wenigstens immer wieder ServiceThread.ProcessRequests(True); abgefragt..

und bei dir steht da auch true, also er soll auf eine message warten...
vielleicht müsste ich meinen dienst mal mit timer realisieren?!
den Timer nutze ich deshalb, weil dieser Dienst im Ursprung pünktlich zur vollen Stunde einen bestimmten Job ausführen sollte. Dafür habe ich mir einen Nachfahren von TTimer geschrieben, der beim Timer.Enable := True das Interval auf die Millisekunden bis zur nächsten vollen Stunde setzt. Aber das ist hier eigentlich nachrangig. Wann und wie oft soll denn Dein Dienst tätig werden. Dann könnte ein Timer durchaus die "richtige" Lösung sein. Ob's die bessere Lösung ist, weiß ich nicht, es war für das konkrete Problem die praktischste Lösung.
  Mit Zitat antworten Zitat
Benutzerbild von cherry
cherry

Registriert seit: 14. Nov 2005
561 Beiträge
 
RAD-Studio 2009 Ent
 
#29

Re: Eigener Dienst beendet nicht korrekt...

  Alt 30. Apr 2009, 10:40
naja, bei dir ist jedenfalls gewährleistet, dass die messages immer abgefangen werden, mit ServiceThread.ProcessRequests(True);.
Dadurch kann bei dir ein solches Problem ja gar nicht bestehen.

Was hälts du den von meiner Thread Variante`?

Delphi-Quellcode:
while not terminated do
begin
  if dienststoppen then
  begin
    TerminateThread(...);
    TerminateThread(...);
    TerminateThread(...);
  end;
  ServiceThread.ProcessRequests(False);
  Sleep(500); // halbe sek. warten
end;
eigentlich ähnlich wie deine on Timer variante...
na?
Ist das nur mein Gefühl, oder ist die ganze Welt verrückt geworden!?
  Mit Zitat antworten Zitat
nahpets
(Gast)

n/a Beiträge
 
#30

Re: Eigener Dienst beendet nicht korrekt...

  Alt 30. Apr 2009, 12:21
Hallo,

mit Threads kenne ich mich jetzt nicht wirklich aus. Es scheint aber so zu sein, dass der Timer einen neuen Thread aufmacht, da andere Dienste von mir mit mehreren Timern arbeiten und dadurch auch mehrere (sehr unterschiedliche) Aufgaben gleichzeitig erledigt werden. Es ist wohl eher Geschmacksache. Bei Deiner Variante werden die Threads wohl von außen gestoppt und Du musst sicherstellen, dass sie auf das Beenden auch zeitnah reagieren. Besteht da nicht eventuell die Gefahr, dass Du das Problem auf eine andere Stelle verschiebst, wenn gerade in einem Thread eine For-Schleife abgearbeitet wird. Ist da sichergestellt, das der Thread auch "mitten" in der For-Schleife beendet wird. Besteht da dann die Möglichkeit, dass inkonsistente Daten übrig bleiben?
Meine (subjektive) Meinung ist: Über einen Schalter kontrolliert aus einer Routine aussteigen, um noch eine bestehende Aufgabe abzuschließen. Du gehst ja im Prinzip her und beendest die Threads nacheinander. Der zweite Thread erfährt also erst nach dem erfolgreichen Beenden des ersten Threads, dass er sich beenden soll, der Dritte nach dem Zweiten.... (Oder läuft das intern parallel ab, sprich: wartet TerminateThread auf das Ende des Threads?) Hier müsstest Du also sicherstellen, dass das alles innerhalb der Timeoutzeit von Windows erfolgreich beendet wird. Nur den Schalter setzen und dann innerhalb der Threads den Schalter zu prüfen, könnte das Beenden (vermutlich) beschleunigen. Inwieweit es sinnvoll ist, aus Threads heraus auf globale Variabeln zuzugreifen, vermag ich nicht definitiv zu beantworten.

Bei einem anderen Dienst habe ich kürzlich (zufällig) festgestellt, dass Windows 30 Sekunden wartet, bevor es einen Dienst "mit der Keule" erschlägt.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 3 von 4     123 4      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:10 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz