Sonjli 6 Posted April 30, 2019 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
Primož Gabrijelčič 223 Posted April 30, 2019 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
Dave Nottage 562 Posted April 30, 2019 Should we assume that the ServiceStop event is fired? Share this post Link to post
Sonjli 6 Posted May 2, 2019 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
Primož Gabrijelčič 223 Posted May 3, 2019 I was able to repeat the problem and I'm looking into it. Share this post Link to post
Primož Gabrijelčič 223 Posted May 6, 2019 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
Sonjli 6 Posted May 6, 2019 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
Primož Gabrijelčič 223 Posted May 6, 2019 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. 1 Share this post Link to post