How to identify an unresponsive process?

2k views Asked by At

I am refactoring a custom process monitoring application for a client that is deployed in Windows Server 2008 R2 and Windows Server 2012 environments.

The monitoring application needs to identify crashed, unresponsive processes (identified as "Not Responding" in the Task Manager), forcefully kill them and restart. The processes monitored can be either Console or Win32-based applications, predominantly Console-based.

The Process.Responding property is of no use in this particular occasion as it determines if the UI is responding (potentially using a similar method "under the hood" as the one below to update this property).

The IsHungAppWindow method is also of no use if it were imported as the Console-based applications do not fulfill the following criteria:

An application is considered to be not responding if it is not waiting for input, is not in startup processing, and has not called PeekMessage within the internal timeout period of 5 seconds.

The Status property of the Win32_Process WMI class is of no use were I monitoring processes using the WMI system classes since:

This property is not implemented and does not get populated for any instance of this class. It is always NULL.

The ExecutionState property of the Win32_Process WMI class is of no use as it appears not to be implemented also. Although not explicitly stated, after running local tests it repeatedly returns NULL and a third party indicates this.

How can I reasonably determine whether or not processes are unresponsive?

1

There are 1 answers

0
Jonathon Ogden On

The best answer and solution I can determine is to monitor Application Error and Application Hang events from the Windows Event Viewer Application log.

As of .NET 3.5, a handy class was implemented to avoid reading and filtering the entire event logs: EventLogWatcher allowing to watch for specific events instead.

Here is a very basic example, filtering by EventID, Level and ApplicationName using an XPath query:

using System.Globalization;
using System.Diagnostics.Eventing.Reader;

EventLogQuery filter = new EventLogQuery("Application", PathType.LogName, "Event[System[Level=2 and (EventID = 1000 or EventID = 1002)] and EventData[Data[1] = \"example.exe\"]]")
EventLogWatcher watcher = new EventLogWatcher(filter);

watcher.EventRecordWritten += Watcher_ApplicationError; // Register our handler
watcher.Enabled = true; // Start delivering events to the handler

private void Watcher_ApplicationError(object sender, EventRecordWrittenEventArgs e) 
{
     String rawId = e.EventRecord.Properties[8].Value.ToString(); // Faulting process id

     Int32 id = -1;
     if (!Int32.TryParse(rawId, out id)) // If not integer, possibly hexadecimal
     {
         if (!Int32.TryParse(rawId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out id)
             return; // Unable to read the process id successfully
     }

     Process unresponsive = Process.GetProcessById(id); // Get the unresponsive process
     unresponsive.Kill(); // Kill it
}

This can easily be expanded upon to filter by the fully qualified, faulty application execution path Properties[10].