Tuesday, October 11, 2005

1331.aspx

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