windows services in .net, auto-restarting?

G

Guest

Hi...

Following the samples online, we implemented a windows service in .Net.
Like most services, there's a worker thread actually doing stuff in the
background. The problem we've run into is how to get the service to exit
when the worker thread has a fatal error *and* get the SCM to invoke the
auto-restart configuration?

The worker thread can error out while the parent thread in the server
process chugs along. We can set the exit code for the service in the worker
thread and then a) call this.Stop() or b) instantiate a ServiceController,
look ourselves up and call Stop(), or c) pull in the win32 dll and make an
unmanaged call to invoke stop. We can get the service to stop, but the
auto-restart configuration doesn't seem to kick in.

Reading old NT/Windows Services docs from win32, there is a line saying that
restart actions are taken *if the SCM wasn't called to Stop() the service*
i.e. only if the process dies a natural death.

So how does one get a .Net windows service just to die when the worker
thread dies?

Thanks
Mark
 
J

Jeffrey Tan[MSFT]

Hi Mark,

Based on my understanding, you wanted to allow the service to leverage the
auto-restarting configuration while exceptions are generated in the
background worker thread. If I have misunderstood you, please feel free to
tell me, thanks.

Do you use .Net1.1 or .Net2.0 Windows Service? Do you catch the crash
exception in your thread proc? Based on my test in a VS2005 service with
auto-restarting configuration, if there is any unhandled exception
generated in the worker thread(without catching), the service process will
terminate and after 1 minite, the SCM will try to restart it again. My test
code is very simple, listed below:

private void ThreadProc()
{
throw new Exception("abc");
}

protected override void OnStart(string[] args)
{
System.Threading.Thread t = new System.Threading.Thread(new
System.Threading.ThreadStart(ThreadProc));
t.Start();
}

Based on my experience, the SCM will take action on the auto-restarting
feature if the service fails. A service fails if its process dies without
the service setting its state to SERVICE_STOPPED. This is the key point.

If the exception is not caught in the ThreadProc, it will certainly crash
the service process without setting status to SERVICE_STOPPED. So the
auto-restarting will take effect.

If you have caught the exception, the Stop() method will not take effect in
our scenario. This is because Stop() method internally calls DeferredStop()
method which uses SetServiceStatus with setting SERVICE_STOPPED(Note
SERVICE_STOPPED is of value 1 in const):

public void Stop()
{
this.DeferredStop();
}

private unsafe void DeferredStop()
{
fixed (NativeMethods.SERVICE_STATUS* service_statusRef1 =
&this.status)
{
int num1 = this.status.currentState;
this.status.checkPoint = 0;
this.status.waitHint = 0;
this.status.currentState = 3;
NativeMethods.SetServiceStatus(this.statusHandle,
service_statusRef1);
try
{
this.OnStop();
this.WriteEventLogEntry(Res.GetString("StopSuccessful"));
this.status.currentState = 1;//This is SERVICE_STOPPED
NativeMethods.SetServiceStatus(this.statusHandle,
service_statusRef1);
....
}
catch (Exception exception2)
{
....
}
}
}
Also, the service main thread ServiceMainCallback will also call
SetServiceStatus with SERVICE_STOPPED. So if the main thread dies normally
or Stop() method is called, the service is recognized as exiting without
failure.

So, to achieve your requirement, we can not allow the main thread to exit
normally, one workaround is catching the exception in ThreadProc and does
the cleanup and save work in the catch handler. Finally, you may invoke
"throw;" keyword again to rethrow the exception. This will force the
service to die as failure, which allow the SCM to auto-restart the service
based on configuration.

Hope it helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Jeffrey...

A couple of us spent a long time googling around on the subject yesterday
and found some of your other posts on other groups (there isn't a clear
favorite group for this kind of question from the titles).

We've got a service using .Net 2.0. At first, the worker thread caught
exceptions and quietly exited which was not the optimal solution since that
left the process alive doing no work. Our next attempt was calling the SCM
via the native method to stop the service from the worker thread. But then
we found that the auto restart didn't kick in. Tried the same thing with
Stop(), creating the ServiceController object and stopping through that, etc.
As you say, the net result was that the SCM considered it a clean stop no
matter what we set the exit code to.

I thought one of the other guys tried throwing an uncaught exception from
the worker thread without success. Ultimately, we settled on
Environment.Exit() from the worker thread; that seemed to do the trick. As
long as we aren't hosting multiple services in the process, it seemed to fit
the bill.

Thanks
Mark


"Jeffrey Tan[MSFT]" said:
Hi Mark,

Based on my understanding, you wanted to allow the service to leverage the
auto-restarting configuration while exceptions are generated in the
background worker thread. If I have misunderstood you, please feel free to
tell me, thanks.

Do you use .Net1.1 or .Net2.0 Windows Service? Do you catch the crash
exception in your thread proc? Based on my test in a VS2005 service with
auto-restarting configuration, if there is any unhandled exception
generated in the worker thread(without catching), the service process will
terminate and after 1 minite, the SCM will try to restart it again. My test
code is very simple, listed below:

private void ThreadProc()
{
throw new Exception("abc");
}

protected override void OnStart(string[] args)
{
System.Threading.Thread t = new System.Threading.Thread(new
System.Threading.ThreadStart(ThreadProc));
t.Start();
}

Based on my experience, the SCM will take action on the auto-restarting
feature if the service fails. A service fails if its process dies without
the service setting its state to SERVICE_STOPPED. This is the key point.

If the exception is not caught in the ThreadProc, it will certainly crash
the service process without setting status to SERVICE_STOPPED. So the
auto-restarting will take effect.

If you have caught the exception, the Stop() method will not take effect in
our scenario. This is because Stop() method internally calls DeferredStop()
method which uses SetServiceStatus with setting SERVICE_STOPPED(Note
SERVICE_STOPPED is of value 1 in const):

public void Stop()
{
this.DeferredStop();
}

private unsafe void DeferredStop()
{
fixed (NativeMethods.SERVICE_STATUS* service_statusRef1 =
&this.status)
{
int num1 = this.status.currentState;
this.status.checkPoint = 0;
this.status.waitHint = 0;
this.status.currentState = 3;
NativeMethods.SetServiceStatus(this.statusHandle,
service_statusRef1);
try
{
this.OnStop();
this.WriteEventLogEntry(Res.GetString("StopSuccessful"));
this.status.currentState = 1;//This is SERVICE_STOPPED
NativeMethods.SetServiceStatus(this.statusHandle,
service_statusRef1);
....
}
catch (Exception exception2)
{
....
}
}
}
Also, the service main thread ServiceMainCallback will also call
SetServiceStatus with SERVICE_STOPPED. So if the main thread dies normally
or Stop() method is called, the service is recognized as exiting without
failure.

So, to achieve your requirement, we can not allow the main thread to exit
normally, one workaround is catching the exception in ThreadProc and does
the cleanup and save work in the catch handler. Finally, you may invoke
"throw;" keyword again to rethrow the exception. This will force the
service to die as failure, which allow the SCM to auto-restart the service
based on configuration.

Hope it helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi Mark,

Thanks for your detailed information. It really makes the problem much
clear.

Yes, Environment.Exit() method immediately transfers into the CLR and will
terminate the entire process and give the underlying operating system the
specified exit code, so it will not allow the main service thread to invoke
SetServiceStatus with SERVICE_STOPPED.

This should be a reliable solution for single-service application, and it
is more graceful and readable than my recommendation of rethowing the
unhandled exception.

Thanks for your sharing.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi Mark,

For your information:

Based on my recently reading to the service model on Vista. There is a
change to the service failure recovery model: a service doesn't have to
crash to have the SCM initiate a failure action.

Basically, a service can handle any unhandled exception and set
FailureActionsOnNonCrashFailures to 1 to enable a service to notify the SCM
to initiate failure actions:
"A service notifies the SCM to queue a failure action by entering the
SERVICE_STOPPED state and setting SetServiceExitCode function's
dwWin32ExitCode parameter to anything other than ERROR_SUCCESS."

However, I do not think .Net has exposed any class to leverage this new
Vista service model, so we still have to p/invoke to get it work.

Please refer to the "Failure Detection and Recovery" section in the page
below for the details:
"Services in Windows Vista"
http://www.microsoft.com/whdc/system/vista/Vista_Services.mspx

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 

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