[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 471
  • Last Modified:

What is the perfect way to run a service application?

Hi,

I'm about to wirte a service application with a timer. So I look aa EE and found examples, but wich one is the proper way.

Br
The 1st one:
procedure TCollectMail.TimerOnTimer(Sender: TObject);
var
  FF: Text;
begin
//  winExec('d:\mail\xa.cmd',SW_HIDE);
 
  AssignFile(FF, 'c:\CollectMail.log');
  if FileExists(log) then begin
    Append(FF);
  end else begin
    Rewrite(FF);
  end;
  Writeln(FF, FormatDateTime('dd.mm.yyyy hh:nn', Now));
  CloseFile(FF);
end;
 
 
procedure TCollectMail.ServiceExecute(Sender: TService);
begin
//  winExec('d:\mail\xa.cmd',SW_SHOWNORMAL);
  Timer.Enabled := True;
  while not Terminated do begin
    ServiceThread.ProcessRequests(False);
  end;
  Timer.Enabled := False;
end;
 
The 2nd one:
procedure TSampleService1.TimerOnTimer(Sender: TObject);
var
  txt : TextFile;
begin
  AssignFile(txt, 'C:\temp\Serv.txt');
  {$I-}
  Append(txt);
  {$I+}
  if IOResult=0 then
  begin
    Writeln(txt, FormatDateTime('yyyy-mm-dd', Date),' ',
                 FormatDateTime('hh:mm:ss', Time), ' .');
    Flush(txt);
    CloseFile(txt);
  end;
  Beep;
end;
 
procedure TSampleService1.ServiceStart(Sender: TService;
  var Started: Boolean);
var
  txt : TextFile;
begin
  Timer:=TTimer.Create(nil);
  Timer.Interval:=10000;
  Timer.OnTimer:=TimerOnTimer;
  AssignFile(txt, 'c:\temp\Serv.txt');
  {$I-}
  Reset(txt);
  {$I+}
  if IOResult <> 0 then
  begin
    Rewrite(txt);
    Writeln(txt, FormatDateTime('yyyy-mm-dd', Date),' ',
                 FormatDateTime('hh:mm:ss', Time), ' Service Started');
    Flush(txt);
  end;
end;

Open in new window

0
QC20N
Asked:
QC20N
  • 9
  • 7
1 Solution
 
QC20NAuthor Commented:
Damn, forgot to tell you that in those 2 exampels it dosen't matter what the OnTimer does. It just the OnExecute and the OnStart I'm interested in.

br.
0
 
2266180Commented:
if I were you, I would just drop a timer on the service and use it as I would from a classic windows applicaiton, dropping the timer on the form ;)
with differences:
- in service start: I start the timer
- in service  stop and pause I stop the timer
- and I would use a
reset/rewrite(f);
try
  read/write from/to file
finally
  closefile(f);
end;
0
 
QC20NAuthor Commented:
Ok. You are saying that I should do a OnStart procedure instaed of a OnExecute. Why? Why not the OnExecute procedure?

And as I said what the exampels do dosen't matter. I'm only interesting on how start the OnTimer and I can see there is 2 ways the OnExecute or the OnStart.

What should be the proper one?

br
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
2266180Commented:
there is no point in me explaining this stuff from 0, so here is a pretty good tutorial on windows services with delphi: http://www.tolderlund.eu/delphi/service/service.htm
an piece of the article on your specific problem is found in the attached code section
There are basically two places where you can put your service code:
In the OnExecute method or the OnStart event.
 
OnExecute method:
Put your code in the TService.OnExecute method. Here you can also create a thread with your code if you want.
Quote from the help under OnExecute:
"Occurs when the thread associated with the service starts up."
"If you are not spawning a new thread to handle individual service requests in an OnStart event handler, this is where you implement the service. When the OnExecute event handler finishes, the service thread terminates. Most OnExecute event handlers contain a loop that calls the service threads ProcessRequests method so that other service requests are not locked out."
 
OnStart event:
Create a thread (TThread) that contains your code and start the thread in the TService.OnStart event.
Quote from the help under OnStart:
"OnStartup occurs when the service first starts up, before the OnExecute event."
"This event should be used to initialize the service. For example, if each service request is handled in a separate thread (a good idea if handling the request takes much time) the thread for a request is spawned in an OnStart event handler."
 
Which method you use is a personal matter, both work fine.
Below is an example of both methods.
 
 
Using OnExecute method
 
procedure TCompanySqlDatabaseSpecialSomething.ServiceExecute(
  Sender: TService);
const
  SecBetweenRuns = 10;
var
  Count: Integer;
begin
  Count := 0;
  while not Terminated do
  begin
    Inc(Count);
    if Count >= SecBetweenRuns then
    begin
      Count := 0;
 
      { place your service code here }
      { this is where the action happens }
      SomeProcedureInAnotherUnit;
 
    end;
    Sleep(1000);
    ServiceThread.ProcessRequests(False);
  end;
end;
 
We loop around in the while-do loop until the service should be terminated, either when the machine is shutting down or the service is stopped from the service applet.
In this example the procedure "SomeProcedureInAnotherUnit" is called every 10 seconds.
Note that we do not use Sleep(10000) in order to wait 10 seconds.
If we did that our service would not be able to responds quickly to commands sent from the SCM (Service Control Manager).
Instead we sleep only for 1 second at a time and use a counter to count how many seconds how gone since the last call to SomeProcedureInAnotherUnit.
You can use the OnStart event if you want to perform some initialization here instead of doing it in the OnExecute event and that allows you to set the Started variable to False if you find that some needed settings is missing and don't want the service to start.
 
Using the OnExecute method this way has it's advantages and drawbacks.
Advantage:
The code is simple. You do not need to create a secondary thread.
Pausing and resuming the service is handled automatically without extra code.
Drawbacks:
The SomeProcedureInAnotherUnit must take only a very short time to finish, it should take no more than a few seconds at the most.
 
The OnExecute method works well if the code takes only short time to finish on each run.
If the code takes a long time to run, you should consider starting a secondary thread in the OnStart event instead.
 
 
Using OnStart event
 
First you need to define your secondary thread class where you put all your code to do what ever it is you want your service to do.
Create the thread as you usually make thread classes. One way is to select the menu item File, New, Other, "Thread Object".
If you do not have any experience with threads you need to get a working knowledge about threads before you continue with the service application.
Tutorials on thread programming in Delphi:
Original, now removed:
http://www.pergolesi.demon.co.uk/prog/threads/ToC.html
Can now be found here:
http://www.eonclash.com/Tutorials/Multithreading/MartinHarvey1.1/ToC.html

Open in new window

0
 
QC20NAuthor Commented:
Yes, that site I have seen, but the Timer has it's own OnTimer event. So it dosen't matter what kind of procedure I choose because the Ontimer do all the stuff, right?
0
 
2266180Commented:
more or less. if you go with the onexecute event, then you must place that loop you posted with while not terminated so that the service doesn't terminate until it si told to.
then in onstart you place timer.enabled=true and in onstop/pause/shutdown you place timer.enabled=false;
OR
you do it in onexecute like this:
timer on
try
  loop here
finally// just in case tehre is an exception while running.
  timer off
end;
0
 
QC20NAuthor Commented:
So either way, both are usefull?
0
 
2266180Commented:
of course. it all depends how you like it. if I were you, I wouldn't even use a timer, I would use a thread. all these are personal choices based on what needs to be done or how you are used to doing things.
in this particular case of developing services, there is no perfect way. tehre are 2 ways and both work and they can be combined as well, and it will still work fne. you just have to choose which way you like it better :)
0
 
QC20NAuthor Commented:
Well, I need to a timer, cause should check an sql db on a certain time. Every 15 min. I need to check my sql db.
0
 
2266180Commented:
you are thinking this wrong. you do not need a timer. you want a timer. it's different.
ask yourself: and what stops you of doing that in a thread? nothing. see below code:

procedure thread.execute;
var i:integerl
begin
  while not terminated do
  begin
    i:=0;
    while (not terminated) and (i<60*15) do// this sleeps for 15 minutes
    begin
      inc(i);
      sleep(1000);// sleep 1 second
    end;
    try
      check DB;
    except
      log error to file or something
    end;
  end;
end;

so you see, it is never the need of something it is jsut the way you are used to doing things. same goes for this particular question: you can do it with onexecute even or without it. it really doens't matter. there is no perfect way.

sure, in your case, since it is a DB thing, I would suggest using a thread especially if the operation on the DB is slow (mnore than a few seconds. it is not advisable that a thread blocks for more than a few seconds.
0
 
QC20NAuthor Commented:
But what Thorlund is telling I should not use a OnExecute method if the if the code takes to long. I don't know at this point how long my code it going to be. But you are saying, in my case, you suggest I use a thread. What I understand about a thread, is that you can more processes running at the same time. Is that wise in my case? I thread one is not finished and a second one is running. What will happen if my ADOQuery hasen't closed the access to the DB before the next one need to use the DB?
0
 
2266180Commented:
>> But what Thorlund is telling I should not use a OnExecute method if the if the code takes to long

that's what I said too.

and you missunderstood this again: you create only one thread. in the service create event (make sure you create it suspended) and destroy it in the service destroy event (make sure to resume it and call waitfor)
you then start the thread in the onstart, stop it in the onstop and onshutdown and suspend it in the onpause event.
0
 
QC20NAuthor Commented:
True.

Maybe I have misunderstod something again, but why not use a komponent (Timer) that do the stuff I want?

And in your exampel, should I not have something like "prossesmessage" or something so the service dosen't use must CPU?
0
 
2266180Commented:
because the timer runs in the service thread. it doens't matter that you code executes fro 5 minutes in the timer event or in the oinexecute event: from the trhead point of view, it's the same thread.

if your code executes fast, below 2 seconds, always, then use a timer, otherwise use a thread.  I am getting sick of explaining the same thing over and over again.

and you still don't understand, do you. you have 3 ways:
- one only with onexecute event
- one without onexecute event (but with onstart/stop/etc)
- and one which mixes the above 2 and should probably not be used if you don't understand them
so in this light of the things, why are you asking me if the processmessage is needed? in one way it is needed, in the other it is not. I explained it, that article explained it, what more do you want? should I get ziolko in to say the excat same thing again? would that make it better?

go, write the code and see it work. this is programming, not philosophy.
0
 
QC20NAuthor Commented:
Ciuly is not a very good serviceminded person. He may be an expert in his field, but serviceminded he is not.
0
 
QC20NAuthor Commented:
I'm not frustrating. I think Ciuly is. Since he's angry, that I'm not fully understand what he is writing.

I will look into the other thing you mention. Al thoug that I do not know what you mean. :) by "Open Questions that you have abandoned."
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 9
  • 7
Tackle projects and never again get stuck behind a technical roadblock.
Join Now