8
votes

I have some windows services that i have written in delphi and they generally work very well, however on occasion i do get an exception thrown that can be considered fatal. When this happens the service is designed to stop.

My question is how do i exit the service in such a way that the SCM will automatically try to restart the service. (I have already set the recovery options for the service in the service manager)

MSDN states

A service is considered failed when it terminates without reporting a status of SERVICE_STOPPED to the service controller.

i have read this blog post Using the Automatic Recovery Features of Windows Services but i am not sure how to implement this in delphi.

i have allready tried the following

  • Setting the ErrCode Property of the TService to a non zero value.
  • Setting the stopped Parameter of the ServiceStop Event to false.
  • Raising an exception in the servicestop event handler.

EDIT 2013-08-06 added code example

Code Now Updated to show working example

Here is the code im using,

procedure TTestService.ServiceExecute(Sender: TService);
begin

  while not (Terminated or FFatalError) do
  begin
    ServiceThread.ProcessRequests(False);
    ReportStatus;
    Sleep(100);
  end;

  if FFatalError then
   Halt(1);

end;

FFatalError is a private boolean field on the TTestService class and is initialized to false on startup, it is only set to true if the worker thread (started in the TTestService.ServiceStart event) terminates with a fatal exception.

here is the OnTerminate event handler for the worker thread.

procedure TTestService.ThdTerm(Sender: Tobject);
var
  E : Exception;
  Thread : TThread;
begin
  Thread := TThread(Sender);

  if (Thread.FatalException <> nil) then
  begin
    E := Exception(Thread.FatalException);
    GetExcCallStack(E);

    EventLog.LogError(Thread.ClassName + ': ID:'+ IntToStr(Thread.ThreadID) +
      ' Stopped Unexpectedly!, '+ NEWLINE + E.ClassName +': ' + E.Message);
    FFatalError := True;
  end;

end;
1
Did you try calling ExitProcess?David Heffernan
"When this happens the service is designed to stop." That could be the problem. You might have to choose between handling the exception or letting it genuinely fail. Perhaps if you post the code that "is designed to stop" the service, we might be able to see more clearly.Sam
Just terminate service process via Task Manager. If SCM restart config for your service is correct, service will be restarted.Alexandr
@Alexandr MikeT is looking for a programmatic way to do itDavid Heffernan
@Sam Build with debug dcus and step into the function. It's an intrinsic. And of course it ends with a call to ExitProcess.David Heffernan

1 Answers

8
votes

The SCM will restart your service if it fails. But all the normal termination modes from a Delphi service do not count as failure. If you could raise an exception from the main service thread that was unhandled, then that would count as a failure.

However, I think the simplest way for you to force a process termination that is treated as a failure is to call ExitProcess. You could equally well call the Delphi RTL function Halt which will ultimately call ExitProcess. However, since your process is probably in a bad state I'd be inclined to go straight to ExitProcess.

As has already been commented, avoiding the exception in the first place would be the ideal solution.