![]() |
Re: Eigener Dienst beendet nicht korrekt...
Leider funktioniert die Geschichte immer noch nicht 100% ig...
Zitat:
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... |
Re: Eigener Dienst beendet nicht korrekt...
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 |
Re: Eigener Dienst beendet nicht korrekt...
Zitat:
Delphi-Quellcode:
funktioniert einwandfrei... beendet immer korrekt
while not terminated do
begin ServiceThread.ProcessRequests(False); Sleep(500); // halbe sek. warten end; aaaaber:
Delphi-Quellcode:
beendet nie korrekt...
while not terminated do
begin ServiceThread.ProcessRequests(False); Sleep(15000); // 15 sek. warten end; 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... |
Re: Eigener Dienst beendet nicht korrekt...
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..." |
Re: Eigener Dienst beendet nicht korrekt...
Zitat:
Braucht ADO da noch was ? Zitat:
Zitat:
das wäre doch kein schöner code; Zitat:
Zitat:
Delphi-Quellcode:
und dann alle aktionen in eigenen threads? ware das eine Idee?
while not terminated do
begin if dienststoppen then begin TerminateThread(...); TerminateThread(...); TerminateThread(...); end; ServiceThread.ProcessRequests(False); Sleep(500); // halbe sek. warten end; 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 :wall: |
Re: Eigener Dienst beendet nicht korrekt...
Hallo,
mit dem Abbruch der For-Schleife hatte ich mir in dieser Form vorgestellt:
Delphi-Quellcode:
Das ist nicht getestet, sondern nur schnell aus einem vorhandenen Service zusammengedaddelt. Hoffe trotzdem, dass es Dir bei der Problemlösung weiterhilft.
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. |
Re: Eigener Dienst beendet nicht korrekt...
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?! |
Re: Eigener Dienst beendet nicht korrekt...
Hallo,
Zitat:
|
Re: Eigener Dienst beendet nicht korrekt...
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:
eigentlich ähnlich wie deine on Timer variante...
while not terminated do
begin if dienststoppen then begin TerminateThread(...); TerminateThread(...); TerminateThread(...); end; ServiceThread.ProcessRequests(False); Sleep(500); // halbe sek. warten end; na? |
Re: Eigener Dienst beendet nicht korrekt...
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. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:13 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz