Windows Service written in c# Hangs

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • mohitkumar
    New Member
    • Mar 2009
    • 4

    Windows Service written in c# Hangs

    Hello All,

    We have 3 windows services written in C#. We use them to process files
    from a folder into database and further to process the data into various SQL
    Tables.

    All the services hang atleast once in a week stopping the entire process. The
    files are queued up in the folders waiting to be processed. The services in
    the Service Control Manager seems to be running but they do not process any
    files. But when the processes are restarted, they run just fine until any one
    hangs again. The following error is written to Event Viewer by Service Control Manager:

    The [Service Name] service terminated unexpectedly. It has done this XX
    time(s). The following corrective action will be taken in 0 milliseconds: Restart Service.


    Any help would be appreciated. (find code below)
    [code=C#]
    using System;
    using System.IO ;
    using System.Threadin g ;
    using System.Xml ;

    namespace XXX.ABCD.Dls.Qu eue
    {
    /// <summary>
    /// A comparison is done between the two Data objects, by individual
    entities
    /// This means only entities that have changed will be updated
    /// this causes less SQL interaction and speeds the whole process up
    /// </summary>
    public class QueueProcess
    {

    // Two XML documents to hold the queue and previous data
    private XmlDocument xmlQueue = new XmlDocument();
    private XmlDocument xmlPrevious = new XmlDocument();

    // A data queue object to process information from the Queue
    private DataQueue oDataQueue = new DataQueue() ;
    // A data previous object to get the last XML processed from the database
    private DataPrevious oDataPrevious = new DataPrevious() ;

    public const int status_begin = 0 ;
    public const int status_end = 999 ;

    private bool stopped = false ;

    // Event argument instances
    private QueueProcess_St atus_EventArgs eQueueProcess_S tatus = new
    QueueProcess_St atus_EventArgs( ) ;

    #region Public

    // Constructor
    public QueueProcess()
    {
    }

    // Make the link between the delegate function and the place in code where
    it is
    called
    public event QueueProcess_St atus QueueProcess_St atus_Event ;

    /// <summary>
    /// Begin polling the folders in the path_incoming for ZIP files
    ///
    /// </summary>
    public void Start()
    {
    Status_Event(st atus_begin, "Queue Thread Begin") ;
    stopped = false ;

    while (true)
    {
    Thread.Sleep(10 0) ;
    Start_QueueProc ess() ;
    if (stopped) break ;
    }
    Status_Event(st atus_end, "Queue Thread End") ;

    }

    public void Stop()
    {
    stopped = true ;
    }

    #endregion

    #region Private functions

    /// <summary>
    /// Method to Start processing QueueProcess
    /// </summary>
    private void Start_QueueProc ess()
    {
    // Process the Queue
    try
    {
    oDataQueue.GetN ext() ;
    // if it is valid process it
    if (oDataQueue.Que ueID != 0)
    {
    try
    {

    #region Load the XML from the Queue and create a ComputerNew object
    // Get the info from the XML
    try
    {
    xmlQueue.LoadXm l(oDataQueue.IN VData) ;
    }
    catch
    {
    xmlQueue.LoadXm l("<XXXX/>") ;
    }
    ComputerNew oComputerNew = new ComputerNew(oDa taQueue.Account ID , ref
    xmlQueue);
    #endregion

    // If AccountID == 0. This means an error has occured loading computer
    new
    if (oComputerNew.A ccountID != 0)
    {
    #region Get the XML from the previous data in the DB and Create a
    ComputerPreviou s object
    oDataPrevious.G et(oComputerNew .AccountID , oComputerNew.Ne tBIOSName);

    // Get the info from the XML
    try
    {
    xmlPrevious.Loa dXml(oDataPrevi ous.INVData) ;
    }
    catch
    {
    xmlPrevious.Loa dXml("<XXXX/>") ;
    }

    ComputerNew oComputerPrevio us = null ;
    try
    {
    oComputerPrevio us = new ComputerNew(0 , ref xmlPrevious) ;
    }
    catch
    {
    Status_Event(10 7,"Error : XML - Could not create computer previous
    object") ;
    }
    #endregion

    #region Compare the New and Previous Prepared XML and if different
    build the collection of data
    // If different then call prepare data on entity new to populate
    collection
    if (oComputerNew.c ustomNew.Prepar edXml != oComputerPrevio us.customNew.
    PreparedXml )
    oComputerNew.cu stomNew.Prepare Data(ref xmlQueue) ; // This sets
    updaterequired in entity

    if (oComputerNew.s ummaryNew.Prepa redXml != oComputerPrevio us.
    summaryNew.Prep aredXml )
    oComputerNew.su mmaryNew.Prepar eData(ref xmlQueue) ; // This sets
    updaterequired in entity

    if (oComputerNew.d isplayNew.Prepa redXml != oComputerPrevio us.
    displayNew.Prep aredXml )
    oComputerNew.di splayNew.Prepar eData(ref xmlQueue) ; // This sets
    updaterequired in entity

    if (oComputerNew.d riveNew.Prepare dXml != oComputerPrevio us.driveNew.
    PreparedXml )
    oComputerNew.dr iveNew.PrepareD ata(ref xmlQueue) ; // This sets
    updaterequired in entity

    if (oComputerNew.n etworkNew.Prepa redXml != oComputerPrevio us.
    networkNew.Prep aredXml )
    oComputerNew.ne tworkNew.Prepar eData(ref xmlQueue) ; // This sets
    updaterequired in entity

    if (oComputerNew.p rinterNew.Prepa redXml != oComputerPrevio us.
    printerNew.Prep aredXml )
    oComputerNew.pr interNew.Prepar eData(ref xmlQueue) ; // This sets
    updaterequired in entity

    if (oComputerNew.s hortcutNew.Prep aredXml != oComputerPrevio us.
    shortcutNew.Pre paredXml )
    oComputerNew.sh ortcutNew.Prepa reData(ref xmlQueue) ; // This sets
    updaterequired in entity

    if (oComputerNew.s oeNew.PreparedX ml != oComputerPrevio us.soeNew.
    PreparedXml )
    oComputerNew.so eNew.PrepareDat a(ref xmlQueue) ; // This sets
    updaterequired in entity

    if (oComputerNew.s oftwareNew.Prep aredXml != oComputerPrevio us.
    softwareNew.Pre paredXml )
    oComputerNew.so ftwareNew.Prepa reData(ref xmlQueue) ; // This sets
    updaterequired in entity

    if (oComputerNew.u sbNew.PreparedX ml != oComputerPrevio us.usbNew.
    PreparedXml )
    oComputerNew.us bNew.PrepareDat a(ref xmlQueue) ; // This sets
    updaterequired in entity

    #endregion

    ComputerCurrent oComputerCurren t = new ComputerCurrent (oComputerNew);

    if (oComputerCurre nt.Compare())
    {
    try
    {
    //Now update the Previous Data from the data queue object
    oDataPrevious.I NVData = oDataQueue.INVD ata ;
    //Set the ID of the entity as the ComputerID
    oDataPrevious.I D = oComputerCurren t.ID;
    oDataPrevious.I nsert();
    }
    catch
    {
    Status_Event(10 8,"Error : Could not update previous data") ;
    }

    try
    {
    oDataQueue.Dele te();
    }
    catch
    {
    Status_Event(10 1,"Error : Could not Delete DataQueue item") ;
    }

    }
    else
    {
    try
    {
    oDataQueue.Fail ed();
    Status_Event(10 2,"Error : Failed to process queue entry") ;
    }
    catch
    {
    Status_Event(10 3,"Error : Could not Mark DataQueue Failed") ;
    }
    }

    }
    else // error creating computernew. No exception AccountID set to 0
    {
    try
    {
    oDataQueue.Fail ed();
    Status_Event(10 5,"Error : XML - Could not create computer new object")
    ;
    }
    catch
    {
    Status_Event(10 6,"Error : Could not Mark DataQueue Failed") ;
    }
    }

    }
    catch
    {
    Status_Event(10 4,"Error : Could not create Computer New Object") ;
    }

    }

    }
    catch (Exception ex)
    {
    Status_Event(10 0,"Error : Could not get next item in DataQueue") ;
    Status_Event(10 0,"Exception : " + ex.Message ) ;
    }
    }

    private void Status_Event(in t code , string message)
    {
    int codeoffset = 2000 ;
    code += codeoffset ;
    eQueueProcess_S tatus.StatusCod e = code ;
    eQueueProcess_S tatus.StatusMes sage = message ;
    QueueProcess_St atus_Event(this ,eQueueProcess_ Status) ;
    }

    #endregion

    #region Properties

    public bool Stopped
    {
    get
    {
    return stopped ;
    }
    }

    #endregion

    #region Event Classes and Delegates

    #region Status Event Class

    public delegate void QueueProcess_St atus( object sender,
    QueueProcess_St atus_EventArgs e) ;

    public class QueueProcess_St atus_EventArgs : EventArgs
    {
    #region Private Variables

    private int statuscode ;
    private string statusmessage ;

    #endregion

    #region Public Properties

    public int StatusCode
    {
    get { return statuscode ; }
    set { statuscode = value ; }
    }

    public string StatusMessage
    {
    get { return statusmessage ; }
    set { statusmessage = value ; }
    }

    #endregion
    }

    #endregion

    #endregion

    }
    }
    [/code]
    Last edited by Plater; Mar 16 '09, 04:43 PM. Reason: code tags
  • PRR
    Recognized Expert Contributor
    • Dec 2007
    • 750

    #2
    Firstly is this your service start function?
    Code:
    public void Start()
             {
                 Status_Event(status_begin, "Queue Thread Begin") ;
                 stopped = false ;
      
                 [B]while (true)[/B]
                 {
                     Thread.Sleep(100) ;
                     Start_QueueProcess() ;
                     if (stopped) break ;    
                 }
                 ....
    I don't see any timers being used... You can use system.timers.t imer or threading timer for services...
    You mentioned that you, "process files....form folder.. into database...furt her to process the data . " Can you explain more here... perhaps the exact procedure?
    Problems that i can guess:
    * Ownership of file can be a problem....for e.g. the service is trying access a file that is locked or being used by another process...
    * You are also connecting to database? connection times out? DB not available...
    * You should also check for Deadlocks....

    This code is fairly wrong.... (especially from a service point of view )
    Code:
    [B]while (true)[/B]
                 {
                     Thread.Sleep(100) ;
                     Start_QueueProcess() ;
                     if (stopped) break ;    
                 }
    Possible solutions:
    * If you intent to call Start_QueueProc ess(), periodically you need to use system.timers.t imer, in case of service...
    * Also you must consider using threads or better asynchronous programming so that you windows service doesn't hang....
    * Make sure your service start returns immediately .... Create a separate thread if needed to execute any function....
    * Lock your functions so that only one instance of function is executing....
    * Periodically do ...
    Code:
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    * Write exception to a log file/ Event log

    Comment

    • mohitkumar
      New Member
      • Mar 2009
      • 4

      #3
      Hi Deepblue,
      thanks for your reply and ideas..

      Firstly is this your service start function?
      This function starts our process..

      Process:
      We process our inventory format files that come into a designated folder(only used by this process). First process reads the file (xml format) and stores the content to a designated table.

      Then second service picks up the xml string, reads data from nodes and further stores this data to several other tables.

      how do i replace Thread.sleep() with System Timer ? does interval() method fit here? how about AutoReset?

      thanks in advance for all your ideas..

      Comment

      • PRR
        Recognized Expert Contributor
        • Dec 2007
        • 750

        #4
        Could you post OnStart(), OnStop() code? I would suggest you replace
        Code:
          while (true)
                      {
                          Thread.Sleep(100) ;
                          Start_QueueProcess() ;
                          if (stopped) break ;    
                      }
        with
        System.Timers.T imer

        "We process our inventory format files that come into a designated folder(only used by this process)."
        As i understand periodically files are created on a folder "A"? and your service scans this folder?
        "First process reads the file (xml format) "
        and connects to DB...? are you sure the DB is on ?

        Comment

        • mohitkumar
          New Member
          • Mar 2009
          • 4

          #5
          Code:
          protected override void OnStart(string[] args)
          {
          #region This code goes into service start
          oServiceLogger.Insert(1000,"DLS Start") ;
          XXX.ABCD.Dal.VersionDetails  oVersion = new XXX.ABCD.Dal.VersionDetails() ;
          oServiceLogger.Insert(1001,"DAL Version : " + oVersion.Get) ;
          #region QueueThread
          oQueueProcess = new QueueProcess() ;
          // Add event handler
          oQueueProcess.QueueProcess_Status_Event +=new XXX.ABCD.Dls.Queue.QueueProcess.QueueProcess_Status(oQueueProcess_QueueProcess_Status_Event);
          // Create and execute the thread
          Thread QueueThread = new Thread(new ThreadStart(oQueueProcess.Start )); 
          QueueThread.Start() ; //Thread start
          QueueThread = null ;
          #endregion
          #endregion
          }
          
          protected override void OnStop()
          {
          	#region This code goes into service stop
          	Stop_Threads() ;
          	oServiceLogger.Insert(1999,"DLS Stop") ;
          	#endregion
          }
          
          private void Stop_Threads()
          {
          	try
          	{
          		if (!oQueueProcess.Stopped) oQueueProcess.Stop() ; 
          	}
          	catch
          	{
          	}
          }
          
          public void Stop()
          {
          	stopped = true ;
          }
          Yes, the service scans this folder for any incoming inventory format files continuosly. ( sleeps for 100 milliseconds, this idea may be wrong).

          Yes, the DB is always on. But as you suggested, deadlocks are potential problem (should I use SQL Trace for checking deadlocks?) hw do I know there is a deadlock?

          Thanks in advance for your ideas..

          Regards,
          Mohith
          Last edited by PRR; Mar 17 '09, 09:41 AM. Reason: added code tags

          Comment

          • PRR
            Recognized Expert Contributor
            • Dec 2007
            • 750

            #6
            Briefly i will explain certain things which may be useful..
            1. System.Timers.T imer:
            Code:
            //Declare the timer 
            System.Timers.Timer myTimer = new System.Timers.Timer();
            
            // initialize in service constructor...  
            myTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
                        myTimer.Interval = 5000;
                        myTimer.Enabled = true;
            As the code suggest declare a system.timers.t imer and initialize it ...

            Code:
            static bool lockTimer = true;
            
            private  void OnTimedEvent(object source, ElapsedEventArgs e)
                    {
                        if (true)
                        {
                            lockTimer = false;
                            CallFun2();
                            
                        }
                    }
            
            public void CallFun2()
                    {
                        try
                        {
                            //Do processing
                            Console.WriteLine("Calling...");
            
                        }
                        catch (Exception ex)
                        {
                            //log exception
                        }
                        finally 
                        {
                            lockTimer = true;
                            //Unlock timer function
                        }
                    }
            This way your function will be executed asynchronously and only once instance will be called ... You can also use locking object( static) ...
            CallFun2 will be your function that you call after a set interval...

            Comment

            • PRR
              Recognized Expert Contributor
              • Dec 2007
              • 750

              #7
              Any tasks that require short processing and can be independently executed can be done by using ThreadPool, such as writing to logs etc...
              Code:
              ThreadPool.QueueUserWorkItem(new WaitCallback(func1));
              
              static void func1(Object o)
                      {            
                          Console.WriteLine("Thread Pool");
                      }

              Comment

              • PRR
                Recognized Expert Contributor
                • Dec 2007
                • 750

                #8
                Last but most important what ever you do, in your service do it as series of asynchronous tasks...Look into Asynchronous Programming Overview

                Comment

                • mohitkumar
                  New Member
                  • Mar 2009
                  • 4

                  #9
                  Hats off to you DeepBlue..

                  Thanks a lot for your time and suggestions...y ou Rock!!


                  Regards,
                  Mohith

                  Comment

                  • PRR
                    Recognized Expert Contributor
                    • Dec 2007
                    • 750

                    #10
                    Welcome... do continue to post your queries on Bytes

                    Comment

                    Working...