How to recycle com+ applications with high call times using .NET
Windows 2003 introduces a new RecycleApplicationInstances method in the COM+ Admin API. It allows transparent recycling of COM+ applications as existing requests are allowed to finish while new requests are routed to a new application instance. A lot better than the ShutDownApplication in Win2k which shuts down the process directly and returns an error to the calling client.
Win2k3 offers several recycling policies in the "Pooling & Recycling" tab of COM+ applications:
- Lifetime limit: The application runs max X minutes before it is recycled
- Memory Limit: The application is recycled if it uses more than X Kilo Bytes of memory. A life saver if you have third party C++ components that leak memory
- Call Limit: Max number of calls before the application is recycled
- Activation Limit: Max number of object activations before the application is recycled
But a very useful limit is missing: max call time. There is no way to tell COM+ to recycle the application if an object blocks for some reason and gives very high call times.Using the egilh.comtracker you an roll your own max call time manager using .NET.
The code below loads the XML returned by egilh.comtracker in a XmlDom and checks the responseTimes. It uses the RecycleApplicationInstances COM+ API to shut down the application if the call time is higher than the configured MAX_CALL_TIME and there are objects in call.
XML returned by egilh.comtracker
<applications>
<application>
<guid>{98CDBB6E-3CAF-46F2-ABE6-EABECD6AA4EB}</guid>
<ID>10</ID>
<processID>1792</processID>
<statistics>
<callsPerSecond>0</callsPerSecond>
<totalCalls>0</totalCalls>
<totalClasses>1</totalClasses>
<totalInstances>1</totalInstances>
</statistics>
<classes>
<class>
<progID>Test.Sleep.1</progID>
<bound>1</bound>
<inCall>0</inCall>
<pooled>-1</pooled>
<references>1</references>
<responseTime>120</responseTime>
<callsCompleted>0</callsCompleted>
<callsFailed>0</callsFailed>
</class>
</classes>
</application>
</applications>
Code for recycling applications with high call times
/// <summary>
/// Check the COM+ Call times, recycling applications with
/// components that have high call times
/// </summary>
private void checkComCallTimes()
{
const int MAX_CALL_TIME = 10000; // Max call time in miliseconds
const int RECYCLE_REASON = 408; // The reason for the recyle. Any number is OK
// Get the call statistics
EGILHCOMTRACKERLib.ComTrackerClass comTracker = new EGILHCOMTRACKERLib.ComTrackerClass();
string statistics = comTracker.getStatistics();
// Load the statistics in a DOM and loop on the call times
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(statistics);
foreach (XmlNode node in xmlDoc.SelectNodes("//class"))
{
// Get class info
string className = node.SelectSingleNode("progID").InnerText.ToLower();
int inCall = System.Convert.ToInt32(node.SelectSingleNode("inCall").InnerText);
long responseTime = System.Convert.ToInt64(node.SelectSingleNode("responseTime").InnerText);
// Recycle if objects are in call and the call time is too high
if (inCall > 0 && responseTime > MAX_CALL_TIME)
{
// get application PID from ../../
XmlNode appNode = node.ParentNode.ParentNode;
recycleApplication(System.Convert.ToInt32(appNode.SelectSingleNode("processID").InnerText),
RECYCLE_REASON);
}
}
}
/// <summary>
/// Recycle a COM+ application instance given the process ID
/// </summary>
/// <param name="processID">Application instance process ID</param>
/// <remarks>Only works on Win2k3 and WinXP. You have to catch
/// various com+ exceptions like "The application has already been recycled"
/// and "The specified application is not longer running"</remarks>
void recycleApplication(int processID, int reason)
{
COMAdmin.COMAdminCatalogClass adminCatalog = new COMAdmin.COMAdminCatalogClass();
// Get instance guid from process id
object instanceGUID = adminCatalog.GetApplicationInstanceIDFromProcessID(processID);
// Wrap it in a single element array
object [] applications = new object[1];
applications[0] = instanceGUID;
object recycleObject = (object) applications;
// Pass reference with list of objects to recycle to RecylceApplicationInstances
adminCatalog.RecycleApplicationInstances(ref recycleObject, reason);
}
The API is difficult to use from VBScript as it requires a Variant pointer to a Variant array that contains the list of application instances to use. The code above only works on Windows 2003. Use the VB Script in How to shut down COM+ applications with high call times with VB and VBScript if you use Windows 2000.
No comments:
Post a Comment