Jump to content
Sonjli

OnTerminated never triggers

Recommended Posts

Hello guys,

I am working to port a NTService with a WebBroker application (wrapping Daniele Teti's DMVC) from TThread style to OTL.

It's almost ok (and amazing, yes!) but in the next code the "OnTerminated" event never triggers (I never see the "Server stopped" string in the log)... What am I wrong?

 

Thank you in advance

 

      ...
	  LServer := TIdHTTPWebBrokerBridge.Create(nil);
      FRunner := CreateTask(
         procedure(const Task: IOmniTask)
         var
            LMvc: TIdHTTPWebBrokerBridge;
            i: Integer;
         begin
            LMvc := Task.Param.ByName('mvc');

            RunServer(8889, LMvc);
            try
               repeat
                  Sleep(25);
                  {$IFDEF DEBUG}
                  inc(i);
                  if (i mod 40) = 0 then
                     Task.Comm.Send(MSG_LOG, 'Keep Alive');
                  {$ENDIF}
               until Task.Terminated;
            finally
               StopServer(LMvc);
            end;
         end
         )
         .SetParameter('mvc', LServer)
         .OnMessage(
         procedure(const Task: IOmniTaskControl; const msg: TOmniMessage)
         begin
            if msg.MsgID = MSG_LOG then
            begin
               Log.Debug(msg.MsgData, '');
               // LogMessage(msg.MsgData, EVENTLOG_INFORMATION_TYPE);
            end;
         end
         )
         .OnTerminated(
         procedure(const Task: IOmniTaskControl)
         begin
            Task.Comm.Send(MSG_LOG, 'Server stopped');
            if Assigned(Task.FatalException) then
            begin
               var ELocal := Task.DetachException;
               Task.Comm.Send(MSG_LOG, Format('...with Errors: "%s"', [ELocal.Message]));
            end;
         end
         );
...
// In the ServiceStart event
...
   FRunner.Run;
...
// In the ServiceStop event
...
   FRunner.Terminate;
...

 

Share this post


Link to post

I can't tell the reason for your problem from the example you've given. Please post a minimal, compilable, and complete project that exhibits the problem and I'll look into it. It would be also good if you can drop dependency on WebBroker when preparing that project.

Share this post


Link to post

Hi,

I attach a mock project with the "OnTerminated" event not firing.

- The project is an NTService, so you have to install with "/install"

- I write the logs (a bit verbose...) on the default Windows Event Monitor (under Windows\Application)

 

To reproduce

- Install

- run the service

- wait a punch of seconds

- Stop the service (not pause, it is not implemented for this purpose)

- Open Event Monitor

- The messages linked to "OTL.NTService" Origin finish with a serie like this:

 

Keep Alive

A try to stop task...

FRunner.ExitCode = 0

ServiceStop

 

You'll never find a "Server stopped in ONTERMINATED" message, that is the one fired inside the "OnTerminated" event.

 

I hope to be clear...

 

Thanks again.

 

PS: I use D10.3.1 but I think the sources can be good for oldest versions.

OmniThreadNTService.zip

Share this post


Link to post

Your task is created in one thread (main service thread) and that thread processes messages sent from the task, including the termination message.

 

The task is stopped from a different thread. ServiceCreate and ServiceStart/ServiceStop are NOT executed from the same thread.

 

The OtlTaskControl code expects that the task will be terminated from the same thread that it was created in. The .Terminate method therefore tries to process all messages waiting in the message queue (for example, the termination message), but it cannot do that as the message queue is not associated with the "ServiceStop" thread but with the "ServiceCreate" thread.

 

After the ServiceStop exits, the main service thread is destroyed and that destroys the IOmniTaskControl object. At that moment, messages from the inter-thread message queue are processed, but they cannot be dispatched anywhere as the main service thread is being terminated. (Because of a DSiWin32.pas bug, messages will still be dispatched and may cause the program to crash. This will be fixed today.)

 

Solution? Just do your OnTerminated processing in ServiceStop.

 

Share this post


Link to post

Hi Primoz,

It's all clear. Very clear.

5 minutes ago, Primož Gabrijelčič said:

The task is stopped from a different thread. ServiceCreate and ServiceStart/ServiceStop are NOT executed from the same thread.

This is a new precious info, for me. Where did you get these infos? Only by debugging?

ServiceCreate is in one thread, and ServiceStart/ServiceStop in second thread or every event is in a separate thread? (so are they three?)

6 minutes ago, Primož Gabrijelčič said:

The OtlTaskControl code expects that the task will be terminated from the same thread that it was created in

This is the second precious info. Some of my test are closed.

 

11 minutes ago, Primož Gabrijelčič said:

Solution? Just do your OnTerminated processing in ServiceStop.

This has perfectly sense

 

Thank you very much.

 

Share this post


Link to post

By debugging, of course. Although, I have to admit, it had me quite stumped for a while.

 

A bit of logging proves that service start and stop both come from the same thread (the first number is the thread id):

 

8996|ServiceCreate
8996|Servizio attivato porta = 8889
17284|ServiceStart
8996|Got message 1024
8996|Keep Alive
8996|Got message 1024
8996|Keep Alive
17284|A try to stop task...
6456|Sending COmniTaskMsg_Terminated
17284|FRunner.ExitCode = 0
17284|ServiceStop
8996|Got Terminated
8996|OnTaskTerminated?
 

8996 is the main service thread, 17284 is the service control thread, 6456 is the thread running the background task.



  • Thanks 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×