My .NET service dows not stop in a controlled way

G

Guest

I developing an application based on some windows services on .NET framework
1.1. Eatch service are a single process service. Each service connects to SQL
Server or Oracle database and derives an customiced TCP server class. I
notised that the SCM calls the OnShutdown method when the system shutsdown
and the OnStop method at service stop from SCM. The service stop from SCM
calls the OnStop with different thread than the Main function and the service
stops in a controlled way after the OnStop returns but the OnShutdons is
called with same thread as the Main during the shutdown or restart cycle and
the process will not be stopped in a controlled way. All database connections
in the application database connection pool will remain open in the Oracle
servcers point of view. This cause an out of available connections for the
services after system reboot. I created a clean service to make shure that no
external thread is locked and added some tracings shown in the code below. I
also attached the output from the trace file. I really hope that someone find
some wrong in my code.
-----------------------
Stefan S
/Thanks on advance

The Threadid are obtained with the Thread.GetHashCode() method.
15:04:09, ThreadId:2 Main Called
15:04:09, ThreadId:5 OnStart Called, and Returns
15:04:17, ThreadId:5 OnStop Called
15:04:17, ThreadId:5 StopService Called
15:04:17, ThreadId:5 StopService Returns
15:04:18, ThreadId:5 OnStop Returns
15:04:18, ThreadId:2 Dispose Called
15:04:18, ThreadId:2 Dispose Returns
15:04:18, ThreadId:2 Main Returns

15:05:16, ThreadId:2 Main Called
15:05:16, ThreadId:5 OnStart Called, and Returns
15:05:50, ThreadId:2 OnShutdown Called
15:05:50, ThreadId:2 StopService Called
15:05:51, ThreadId:2 StopService Returns
15:05:51, ThreadId:2 OnShutdown Returns

public class C_TstSvc : ServiceBase
{
Thread oStartThread;
///--------------------------------------------------------------------
/// Constructor
///
/// Parameters:
/// void
///--------------------------------------------------------------------
public C_TstSvc()
{
ServiceName = "Test_Server";
this.CanStop = true;
this.CanShutdown = true;
}

///--------------------------------------------------------------------
/// The main entry point for the service
///
/// Parameters:
/// void
///--------------------------------------------------------------------
static void Main()
{
Log( "Main Called");
System.ServiceProcess.ServiceBase oServiceHanlder = new C_TstSvc();

System.ServiceProcess.ServiceBase.Run( oServiceHanlder);
Log( "Main Returns");
}

///--------------------------------------------------------------------
/// Startup the Tst as service
///
/// Parameters:
/// void
///--------------------------------------------------------------------
protected override void OnStart(string[] args)
{
Log( "OnStart Called, and Returns");
oStartThread = Thread.CurrentThread;
}

///--------------------------------------------------------------------
/// Stop the Tst service
///
/// Parameters:
/// void
///--------------------------------------------------------------------
protected override void OnStop()
{
Log( "OnStop Called");
StopService();
Log( "OnStop Returns");
}

///--------------------------------------------------------------------
/// Called when system shuts down
///
/// Parameters:
/// void
///--------------------------------------------------------------------
protected override void OnShutdown()
{
Log( "OnShutdown Called");
StopService();
Log( "OnShutdown Returns");
oStartThread.Abort();
}

///--------------------------------------------------------------------
/// Called when system shuts down
///
/// Parameters:
/// void
///--------------------------------------------------------------------
private void StopService()
{
Log( "StopService Called");
Thread.Sleep( 500);
Log( "StopService Returns");
}
static private void Log( string sMsg)
{
Thread iCurrentTread = System.Threading.Thread.CurrentThread;
StreamWriter m_oFileWriter;
m_oFileWriter = File.AppendText( "c:\\Aniware\\Test\\TestService.log");
m_oFileWriter.NewLine = "\r\n";
m_oFileWriter.WriteLine( DateTime.Now.ToLongTimeString() + ", ThreadId:"
+ iCurrentTread.GetHashCode() + " " + sMsg);
m_oFileWriter.Close();
}

///--------------------------------------------------------------------
/// Clean up resourses állocated by this object
///
/// Parameters:
/// void
///--------------------------------------------------------------------
protected override void Dispose(bool disposing)
{
Log( "Dispose Called");
base.Dispose (disposing);
Log( "Dispose Returns");
}
}
 
W

Walter Wang [MSFT]

Hi Stefan,

Sorry for delayed reply.

I suggest logging the ThreadId using Thread.ManagedThreadId instead of
Thread.GetHashCode since GetHashCode doesn't produce unique code everytime.

Based on my understanding, the OnShutdown is called by ServiceBase using an
asynchronous call. If the service process doesn't exit itself within a
timeout, it will be killed by SCM -- in which case will cause data loss or
unclosed resource. I believe this timeout is specified here:
HKLM\System\CurrentControlSet\Control, the WaitToKillServiceTimeout value.
What's expected time will be required to clean up all your threads and
resources?

#How to Increase Shutdown Time for Services to Close Properly
http://support.microsoft.com/kb/146092

I'm still not quite clear about how your threads are using and closing the
database connections when starting and stopping, would you please post more
code? Thanks.

Sincerely,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications. If you are using Outlook Express, please make sure you clear the
check box "Tools/Options/Read: Get 300 headers at a time" to see your reply
promptly.

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.
 
S

Solje

Thank you for answer.

The code in by first post is the only code I have except the project
solution and assembly information file.

You wrote that my process shall exits it self. I canot understand the
different between stop of service from SCM and system shut down from
the
service point of view. How shall my service do exit self, is there
any
methods to use for that purpose. The method must let the garbage
colection do
its work before the process exits.


:

Click to show or hide original message or reply text.
 
W

Walter Wang [MSFT]

Hi Stefan,

Sorry for the confusion. What I meant in my last reply is that: a service
is considered to be ready to be closed when its status set to
SERVICE_STOPPED; if its status is not set to this status in the timeout, it
will be killed by SCM.

However, this could only be one possibility of your issue. Since you
mentioned that your OnStop is working correctly, I guess your cleanup phase
may not that long. Anyway, would you please post more code of your service
so that I can help you further troubleshooting. Thanks.

By the way, I've also find a similar thread to this issue which you may
find useful:

#Service Stop timeout setting - .NET C#
http://www.thescripts.com/forum/thread274008.html

Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
S

Solje

using System;
using System.IO;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Configuration.Install;
using System.Threading;

namespace TstSvc
{

///--------------------------------------------------------------------
/// Handle Tst service
///
/// 05-05-31 Stefan Söljemo
///--------------------------------------------------------------------
public class C_TstSvc : ServiceBase
{
Thread oStartThread;

///--------------------------------------------------------------------
/// Constructor
///
/// Parameters:
/// void
///--------------------------------------------------------------------
public C_TstSvc()
{
ServiceName = "Test_Server";
this.CanStop = true;
this.CanShutdown = true;
}


///--------------------------------------------------------------------
/// The main entry point for the service
///
/// Parameters:
/// void
///--------------------------------------------------------------------
static void Main()
{
Log( "Main Called");
System.ServiceProcess.ServiceBase oServiceHanlder = new
C_TstSvc();

System.ServiceProcess.ServiceBase.Run( oServiceHanlder);
Log( "Main Returns");
}


///--------------------------------------------------------------------
/// Startup the Tst as service
///
/// Parameters:
/// void
///--------------------------------------------------------------------
protected override void OnStart(string[] args)
{
Log( "OnStart Called, and Returns");
oStartThread = Thread.CurrentThread;
}


///--------------------------------------------------------------------
/// Stop the Tst service
///
/// Parameters:
/// void
///--------------------------------------------------------------------
protected override void OnStop()
{
Log( "OnStop Called");
StopService();
Log( "OnStop Returns");
}


///--------------------------------------------------------------------
/// Called when system shuts down
///
/// Parameters:
/// void
///--------------------------------------------------------------------
protected override void OnShutdown()
{
Log( "OnShutdown Called");
StopService();
Log( "OnShutdown Returns");
oStartThread.Abort();
}


///--------------------------------------------------------------------
/// Called when system shuts down
///
/// Parameters:
/// void
///--------------------------------------------------------------------
private void StopService()
{
Log( "StopService Called");
Thread.Sleep( 500);
Log( "StopService Returns");
}

static private void Log( string sMsg)
{
Thread iCurrentTread =
System.Threading.Thread.CurrentThread;
StreamWriter m_oFileWriter;
m_oFileWriter = File.AppendText( "c:\\Aniware\\Test\
\TestService.log");
m_oFileWriter.NewLine = "\r\n";
m_oFileWriter.WriteLine( DateTime.Now.ToLongTimeString() + ",
ThreadId:" + iCurrentTread.GetHashCode() + " " + sMsg);
m_oFileWriter.Close();
}


///--------------------------------------------------------------------
/// Clean up resourses állocated by this object
///
/// Parameters:
/// void
///--------------------------------------------------------------------
protected override void Dispose(bool disposing)
{

Log( "Dispose Called");
base.Dispose (disposing);
Log( "Dispose Returns");
}
}


///--------------------------------------------------------------------
/// Handle installation of the Tst service
///
/// 05-05-31 Stefan Söljemo
///--------------------------------------------------------------------
[RunInstaller(true)]
public class TstSvcInstaller : Installer
{
private ServiceProcessInstaller TstProcInstaller;
private ServiceInstaller TstServInstaller;


public TstSvcInstaller()
{
TstProcInstaller = new ServiceProcessInstaller();
TstServInstaller = new ServiceInstaller();

//---------------------------
// TstProcInstaller
//---------------------------
TstProcInstaller.Account = ServiceAccount.LocalSystem;
TstProcInstaller.Password = null;
TstProcInstaller.Username = null;

//---------------------------
// TstServInstaller
//---------------------------
TstServInstaller.ServiceName = "Test_Server";
TstServInstaller.DisplayName = "Test_Server";


//---------------------------
// TstSvcInstaller
//---------------------------
Installers.Add( TstProcInstaller);
Installers.Add( TstServInstaller);
}
}
}
 
G

Guest

Thank you for answer.

The code in by first post is the only code I have except the project
solution and assembly information file.

You wrote that my process shall exits it self. I canot understand the
different between stop of service from SCM and system shut down from the
service point of view. How shall my service do exit self, is there any
methods to use for that purpose. The method must let the garbage colection do
its work before the process exits.
 
W

Walter Wang [MSFT]

Hi Stefan,

Thanks for the complete code listing.

Based on my understanding, you have two questions in summary:

1) Why the OnShutdown gets called on the main thread and OnStop gets called
on a new thread
2) Why you wasn't able to release unmanaged resources in case of OnShutdown.

Actually I get different test result on my side:

4:11:38 PM,ThreadId:3 Main Called
4:11:38 PM,ThreadId:6 OnStart Called, and Returns
4:11:57 PM,ThreadId:3 OnShutdown Called
4:11:57 PM,ThreadId:3 StopService Called
4:11:58 PM,ThreadId:3 StopService Returns
4:11:58 PM,ThreadId:3 OnShutdown Returns

4:15:16 PM,ThreadId:3 Main Called
4:15:16 PM,ThreadId:6 OnStart Called, and Returns
4:15:23 PM,ThreadId:3 OnStop Called
4:15:23 PM,ThreadId:3 StopService Called
4:15:24 PM,ThreadId:3 StopService Returns
4:15:24 PM,ThreadId:3 OnStop Returns
4:15:24 PM,ThreadId:3 Dispose Called
4:15:24 PM,ThreadId:3 Dispose Returns
4:15:24 PM,ThreadId:3 Main Returns


As you can see, on my side both OnStop and OnShutdown executes on the main
thread.

Actually I don't think this thread thing is related to the un-released
resources. I can see you're directly calling the main thread.Abort() in
OnShutdown: this of course will cause the main thread to terminate
immediately and its Dispose() will not get called. Is this the cause that
you're seeing un-released resources?

By the way, sorry about previous reply of the ManagedThreadId property, the
property is new in .NET 2.0 and I previously not realized that you're
referring to .NET 1.1 (My test result above is from .NET 1.1 assembly).


Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
W

Walter Wang [MSFT]

Hi Stefan,

Have you seen my last reply? Does it help? Please feel free to let me know
if there's anything unclear or if I've misunderstood anything. Thanks.


Regards,
Walter Wang ([email protected], remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

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