Windows service processing pattern

R

Russ McDaniel

Originally posted to microsoft.public.dotnet.distributed_apps with no
response. Reposted here with additional thoughts.
---

Hello,

I'm writing a Windows service which performs some potentially long-running,
uninterruptable processes. When the service starts, I create a separate
worker thread to perform the work so as to not block the service control
manager upon startup. The design quandry I'm running into though is how best
to stop the service while it may be in the middle of a long-running process
that I do not wish to terminate.

My options as I see it are as follows:

1. During the service stop call, set my process state to indicate to the
worker thread that it should exit at the next opportunity. Then call
Thread.Join to wait for the process to complete. This doesn't really seem
like a viable option since it will likely cause the service control manager
to timeout.

2. During the service stop call, set my process state to indicate to the
worker thread that it should exit at the next opportunity. Exit immediately
and allow the thread to run its course while the service control manager
assumes that my service has stopped. Meanwhile, the service may continue to
run for a while until the current process completes. There are potential
problems here as well including if the user would attempt to restart the
service immediately while the process is still running.

One idea to mitigate the restart problem might be to use a Mutex to prevent
multiple instances of the app from running. With some extra work, it could
signal the original process to continue running if it is waiting to stop.

Does number 2 sound reasonable? Are there other ways I can approach this?

Regards,
Russ
 
U

UAError

Russ McDaniel said:
Originally posted to microsoft.public.dotnet.distributed_apps with no
response. Reposted here with additional thoughts.
---

Hello,

I'm writing a Windows service which performs some potentially long-running,
uninterruptable processes. When the service starts, I create a separate
worker thread to perform the work so as to not block the service control
manager upon startup. The design quandry I'm running into though is how best
to stop the service while it may be in the middle of a long-running process
that I do not wish to terminate.

My options as I see it are as follows:

1. During the service stop call, set my process state to indicate to the
worker thread that it should exit at the next opportunity. Then call
Thread.Join to wait for the process to complete. This doesn't really seem
like a viable option since it will likely cause the service control manager
to timeout.
I would agree, the SCM does get ruthless.
2. During the service stop call, set my process state to indicate to the
worker thread that it should exit at the next opportunity. Exit immediately
and allow the thread to run its course while the service control manager
assumes that my service has stopped.

Somehow I don't see how you could fool the SCM for very long
- its going to terminate the service process.
Meanwhile, the service may continue to
run for a while until the current process completes. There are potential
problems here as well including if the user would attempt to restart the
service immediately while the process is still running.

One idea to mitigate the restart problem might be to use a Mutex to prevent
multiple instances of the app from running. With some extra work, it could
signal the original process to continue running if it is waiting to stop.

Does number 2 sound reasonable? Are there other ways I can approach this?

Regards,
Russ

While I'm not sure how legitimate the requirement is to want
to stop a service, while allowing a long running task to
complete (what if the machine is shutting down? You are not
going to get to complete the task anyway) consider splitting
the service into a service and a worker process. When the
service starts up:

- Service checks for the existance of worker process. If
worker process does not exist, skip to last step.

- Attempt to communicate with the existing worker process.
if this fails after a number of (configurable) attempts each
spaced with by a (configurable) time interval, terminate the
worker process, then skip to last step.

- Once the worker process responds, queue up new requests
with the intention of fowarding them later to the new worker
process. In regular (configurable) intervals query the
pre-existing process for evidence of progress. If it fails
to show progress terminate the worker process and skip to
last step.

- Proceed once the existing worker process exits.

- Start new worker process. Issue any queued up requests.



In effect your service would be acting as a kinder, gentler
SCM.

You may choose to start the new process before the existing
one completes - but then you have to handle the added
complexity of managing (potentially) multiple pre-existing
processes and terminating them in case they stop showing any
progress.
 
R

Russ McDaniel

Thanks for your suggestions. It may be a little too sophisticated for the
application in question, but I'll see if it makes sense to incorporate any
of it into my current design. With regard to this point:
Somehow I don't see how you could fool the SCM for very long
- its going to terminate the service process.

I've actually tested this scenario. The SCM doesn't appear to care about
what the process is actually doing, it only cares about what the process
says it's doing. For example, my shutdown mechanism in the Stop event
handler is to simply flip my internal processing state from Started to
Stopping. The main processing loop of my worker thread in my service then
exits when it gets around to inspecting its process state on the next loop
iteration.

Since the Stop event handler immediately returns, the SCM assumes my service
stopped and doesn't wait or complain. Meanwhile, my service process is still
winding down in the background. Granted, if the system is shutting down,
it's going to get killed anyway, but at least it has a mechanism for
shutting down gracefully if it is manually stopped.

Thanks again,
Russ
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top