C# – AppDomains vs. a robust server

appdomainc

after doing some research it seems that AppDomains are not really a tool for building a hosting server. From my understanding, the hosting server will still crash if there is an unhandled exception in a created AppDomain (if the exception is thrown from a thread in the created AppDomain). So in that case if the hosting server hosts a service which leaks exceptions this will bring down the default AppDomain as well.

So I guess from a server architecture point-of-view there is nothing better than creating child processes and monitoring them.

Is that correct or am I missing something with AppDomains?

thanks,
Christoph

Best Answer

If you can control the threads created in the other AppDomain, you can also handle exceptions by using catch-all blocks in the thread main method.

Other than that, as long as you use the default host, I believe that your assumption is correct. However, if you host the runtime yourself, you can also handle unhandled exceptions.

From a forum post on the topic:

Well, it is possible. You'd have to create your own CLR host. That starts with ICorBindToRuntimeEx(). You get to have full control of AppDomains that throw exceptions. And it's being used by MSFT software like ASP.NET and SQL Server 2005. When you write a service, you are working with the default CLR host implementation and it terminates the process when any unhandled exception is raised, regardless of what AppDomain caused the exception.

Problem is, hosts like ASP.NET and SQL server have a very well defined code execution path. In a web server, managed code runs because of a page request. In a dbase server, it runs because of a query. When something bad happens, they have the luxury of simply aborting everything that the request started (killing the AppDomain) and returning a "sorry, couldn't do it" status back to the client. You might have seen it, crashing the forums server on the old web site was pretty trivial but didn't stop it from serving other requests. Not actually 100% sure about that.

Your service implementation is probably not nearly as clean. I can't tell, you didn't say anything about it. It general, there's a problem with aborting a thread. You always have to abort a thread when there's an unhandled exception. A service typically has one thread, started by the OnStart() method. Aborting it kills the server until somebody stops and starts it again.

You can definitely make it more resilient than that, you could start a "master" thread that launches child threads in response to external events that makes your service do its job. Having a child thread terminated because of an unhandled exception is something you could possibly recover from. But then, if you make that next step, why not have the child thread catch an exception and pass it back to the master thread so it can make an intelligent decision about what to do next.

The cold hard fact of the default CLR host is: if you are not willing to deal with failure, it is not going to do the job for you. And it shouldn't, the .NET 1.x behavior to threads that died with exceptions was a major mistake that got corrected in .NET 2.0.

You know what to do: handle failure. Or write you own host. Or accept that things could be beyond your control and log a good error message so you can tell your customer what to do. I'd strongly recommend the latter.