Correctly shutting down an appdomain?

N

nickdu

I seem to have an intermittant problem shutting down an appdomain. I say
this because sometimes my application is still running when it thinks it has
shutdown. Here is my scenario:

I've written a .NET service. I pass an argument to this service specifying
the service name. My Service.OnStart() creates an application domain so that
I can set the application configuration file to the '<service name>.config'.
It then creates a server object in this appdomain. This server object
provides the functionality of the application. This server object exposes a
Stopped event so that the service can get notified when the server has
stopped so that it can stop the service.

This seems to work many times. However, there are times when I see the
event in the event log that the server has stopped yet the service is still
running. Am I doing something wrong in shutting down the appdomain and/or
service?

Below is a snippet of the code:

..
..
..
[Serializable]
public class ServerFactory : MarshalByRefObject
{
public ServerFactory()
{
}

public Server Create()
{
// Create from configuration.

return (Server) ConfigurationManager.GetSection("eventProcessor");
}
}

public class Service : ServiceBase
{
private AppDomain _domain;
private Server _server;
private delegate void Control();

private void OnStopped(object sender, EventArgs args)
{
Control control = this.Stop;
control.BeginInvoke(null, null);
// Stop();
}

protected override void OnStart(string[] args)
{
try
{
args = Environment.GetCommandLineArgs();
if (args.Length != 2)
throw(new InvalidOperationException("Missing service name
argument."));

// Create AppDomain.

AppDomainSetup setup = new AppDomainSetup();
setup.ConfigurationFile = args[1] + ".config";
this._domain = AppDomain.CreateDomain("Service",
AppDomain.CurrentDomain.Evidence,
setup);

// Create factory in domain and have it create the server.

ServerFactory factory = (ServerFactory)
this._domain.CreateInstanceAndUnwrap(
Assembly.GetExecutingAssembly().FullName,
typeof(ServerFactory).FullName);
this._server = factory.Create();

/*
// Create from configuration.

this._server = (Server)
ConfigurationManager.GetSection("eventProcessor");
*/
// Fail if no configuration found.

if (this._server == null)
throw(new InvalidOperationException("Missing EventProcessor
configuration."));

this._server.Stopped += OnStopped;
this._server.Start(args[1]);
}
catch(Exception e)
{
try
{
EventLog.WriteEntry((args.Length != 2) ?
Server.EventSourceName : args[1],
string.Format("Failed starting EventProcessor: {0}",
e.ToString()),
EventLogEntryType.Error);
}
catch(Exception)
{
}
if (this._server != null)
{
this._server.Stopped -= OnStopped;
this._server = null;
}
AppDomain.Unload(this._domain);
throw;
}
}

protected override void OnStop()
{
if (this._server != null)
{
this._server.Stopped -= OnStopped;
this._server.Stop();
this._server = null;
}
AppDomain.Unload(this._domain);
}

public override object InitializeLifetimeService()
{
return null;
}

public static void Main()
{
ServiceBase.Run(new Service());
}
}

--
Thanks,
Nick

(e-mail address removed)
remove "nospam" change community. to msn.com
 
J

Jie Wang [MSFT]

Hello Nick,

I'm not sure why your service sometimes doesn't stop running, because I
don't know the details inside your Server class... However, I can provide
some information regarding the ServiceBase.OnStop method and the
AppDomain.Unload method, hope these information will help you on the issue.

The first thing I need to mention is the AppDomain.Unload method.

If you're developing your service on .NET 2.0 or higher, you should notice
the Remarks section in the Unload method's document:

** Begin Quote **

In the .NET Framework version 2.0 there is a thread dedicated to unloading
application domains. This improves reliability, especially when the .NET
Framework is hosted. When a thread calls Unload, the target domain is
marked for unloading. The dedicated thread attempts to unload the domain,
and all threads in the domain are aborted. If a thread does not abort, for
example because it is executing unmanaged code, or because it is executing
a finally block, then after a period of time a
CannotUnloadAppDomainException is thrown in the thread that originally
called Unload. If the thread that could not be aborted eventually ends, the
target domain is not unloaded. Thus, in the .NET Framework version 2.0
domain is not guaranteed to unload, because it might not be possible to
terminate executing threads.

** End Quote **

That means even you call the AppDomain.Unload(_domain), the "_domain" could
be failed to be unloaded. And there could be a
CannotUnloadAppDomainException or other exceptions raised, and since your
OnStop method doesn't handle any exceptions, the stop operation will fail
in case of any exceptions.

Besides the Unload method, is it possible that the Server.Stop method
raises any exceptions?

And since you call the Service.Stop async in OnStopped, it is also possible
that a ThreadAbortException being raised when code in Server is still
executing and the AppDomain.Unload starts to kill the threads in _domain.

Have you looked at the Application Logs in the Event Viewer? Is there any
error regarding exceptions in the OnStop method?

So could you try just remove the AppDomain.Unload from the OnStop code? If
your application is a hosted service, the AppDomain that run the service
will be unloaded automatically, hence everything inside your AppDomain
including your own "_domain" will be released by the system. You don't have
to manually unload it unless I missed something here.

Please check the log for any exceptions during OnStop and try remove the
Unload, and let me know if that works for you.

Thanks,

Jie Wang

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days 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. 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/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

Jie Wang [MSFT]

Hi Nick,

How's going on the issue?

If there is anything I can help on, please let me know.

Thanks,

Jie Wang

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days 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. 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/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
N

nickdu

I took your advice and removed the call to AppDomain.Unload(). While I agree
that it's probably a good idea to remove this, it didn't solve the problem.
I eventually figured out the problem.

I use a mutex in my Server class to ensure that only one instance is running
at a time. The problem is that when the Server encounters an error and
attempts to stop itself it does so via an async delegate since the thread
that wants to stop the server is one of the worker threads and the Stop()
method sets a shutdown event and waits for all worker threads to stop. Thus
calling Stop() synchronously would result in a deadlock. The problem is that
the Stop() method releases the mutext. However since I'm calling Stop() via
an async delegate it's most likely running on a thread other than the one
which Start() ran on and thus is not the same thread that owns the mutex and
therefore ReleaseMutex() throws an exception and I don't finish the shutdown
sequence.

The solution I used to fix this was to use a named event as opposed to a
named mutex. I just need some interprocess resource which I can use to
determine if another instance is running.

--
Thanks,
Nick

(e-mail address removed)
remove "nospam" change community. to msn.com


"Jie Wang [MSFT]" said:
Hi Nick,

How's going on the issue?

If there is anything I can help on, please let me know.

Thanks,

Jie Wang

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days 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. 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/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

Jie Wang [MSFT]

Hi Nick,

Good to know you fixed the problem. :)

So maybe in the OnStop method we should also take care of any exceptions so
unhandled exceptions won't prevent the service being shut down.

Best regards,
Jie Wang

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days 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. 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/en-us/subscriptions/aa948874.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