By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,538 Members | 869 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,538 IT Pros & Developers. It's quick & easy.

Windows Service written in c# Hangs

P: 4
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)
Expand|Select|Wrap|Line Numbers
  1. using System;
  2. using System.IO ;
  3. using System.Threading ;
  4. using System.Xml ;
  5.  
  6. namespace XXX.ABCD.Dls.Queue
  7. {
  8.     /// <summary>
  9.     /// A comparison is done between the two Data objects, by individual
  10. entities
  11.     /// This means only entities that have changed will be updated
  12.     /// this causes less SQL interaction and speeds the whole process up
  13.     /// </summary>
  14.     public class QueueProcess
  15.     {
  16.  
  17.         // Two XML documents to hold the queue and previous data
  18.         private XmlDocument xmlQueue = new XmlDocument();
  19.         private XmlDocument xmlPrevious = new XmlDocument();
  20.  
  21.         // A data queue object to process information from the Queue
  22.         private DataQueue oDataQueue = new DataQueue() ;
  23.         // A data previous object to get the last XML processed from the database
  24.         private DataPrevious oDataPrevious = new DataPrevious() ;
  25.  
  26.         public const int status_begin = 0 ;
  27.         public const int status_end = 999 ;
  28.  
  29.         private bool stopped = false ;
  30.  
  31.         // Event argument instances
  32.         private QueueProcess_Status_EventArgs eQueueProcess_Status = new 
  33. QueueProcess_Status_EventArgs() ;
  34.  
  35.         #region Public
  36.  
  37.         // Constructor
  38.         public QueueProcess()
  39.         {
  40.         }
  41.  
  42.         // Make the link between the delegate function and the place in code where
  43. it is 
  44.                                called
  45.         public event QueueProcess_Status QueueProcess_Status_Event ;
  46.  
  47.         /// <summary>
  48.         /// Begin polling the  folders in the path_incoming for ZIP files
  49.         /// 
  50.         /// </summary>
  51.         public void Start()
  52.         {
  53.             Status_Event(status_begin, "Queue Thread Begin") ;
  54.             stopped = false ;
  55.  
  56.             while (true)
  57.             {
  58.                 Thread.Sleep(100) ;
  59.                 Start_QueueProcess() ;
  60.                 if (stopped) break ;    
  61.             }
  62.             Status_Event(status_end, "Queue Thread End") ;
  63.  
  64.         }
  65.  
  66.         public void Stop()
  67.         {
  68.             stopped = true ;
  69.         }
  70.  
  71.         #endregion
  72.  
  73.         #region Private functions
  74.  
  75.         /// <summary>
  76.         /// Method to Start processing QueueProcess
  77.         /// </summary>
  78.         private void Start_QueueProcess()
  79.         {
  80.             // Process the Queue
  81.             try
  82.             {
  83.                 oDataQueue.GetNext() ;
  84.                 // if it is valid process it
  85.                 if (oDataQueue.QueueID != 0)
  86.                 {
  87.                     try
  88.                     {
  89.  
  90.                         #region Load the XML from the Queue and create a ComputerNew object
  91.                         // Get the info from the XML
  92.                         try
  93.                         {
  94.                             xmlQueue.LoadXml(oDataQueue.INVData) ;
  95.                         }
  96.                         catch
  97.                         {
  98.                             xmlQueue.LoadXml("<XXXX/>") ;
  99.                         }
  100.                         ComputerNew oComputerNew = new ComputerNew(oDataQueue.AccountID , ref
  101. xmlQueue);
  102.                         #endregion
  103.  
  104.                         // If AccountID == 0. This means an error has occured loading computer
  105. new
  106.                         if (oComputerNew.AccountID != 0)
  107.                         {
  108.                             #region Get the XML from the previous data in the DB and Create a
  109. ComputerPrevious object
  110.                             oDataPrevious.Get(oComputerNew.AccountID , oComputerNew.NetBIOSName);
  111.  
  112.                             // Get the info from the XML
  113.                             try
  114.                             {
  115.                                 xmlPrevious.LoadXml(oDataPrevious.INVData) ;
  116.                             }
  117.                             catch
  118.                             {
  119.                                 xmlPrevious.LoadXml("<XXXX/>") ;
  120.                             }
  121.  
  122.                             ComputerNew oComputerPrevious = null ;
  123.                             try
  124.                             {
  125.                                 oComputerPrevious = new ComputerNew(0 , ref xmlPrevious) ;
  126.                             }
  127.                             catch
  128.                             {
  129.                                 Status_Event(107,"Error : XML - Could not create computer previous
  130. object") ;
  131.                             }
  132.                             #endregion
  133.  
  134.                             #region Compare the New and Previous Prepared XML and if different
  135. build the collection of data
  136.                             // If different then call prepare data on entity new to populate
  137. collection
  138.                             if (oComputerNew.customNew.PreparedXml != oComputerPrevious.customNew.
  139. PreparedXml )
  140.                                 oComputerNew.customNew.PrepareData(ref xmlQueue) ; // This sets
  141. updaterequired in entity
  142.  
  143.                             if (oComputerNew.summaryNew.PreparedXml != oComputerPrevious.
  144. summaryNew.PreparedXml )
  145.                                 oComputerNew.summaryNew.PrepareData(ref xmlQueue) ; // This sets
  146. updaterequired in entity
  147.  
  148.                             if (oComputerNew.displayNew.PreparedXml != oComputerPrevious.
  149. displayNew.PreparedXml )
  150.                                 oComputerNew.displayNew.PrepareData(ref xmlQueue) ; // This sets
  151. updaterequired in entity
  152.  
  153.                             if (oComputerNew.driveNew.PreparedXml != oComputerPrevious.driveNew.
  154. PreparedXml )
  155.                                 oComputerNew.driveNew.PrepareData(ref xmlQueue) ; // This sets
  156. updaterequired in entity
  157.  
  158.                             if (oComputerNew.networkNew.PreparedXml != oComputerPrevious.
  159. networkNew.PreparedXml )
  160.                                 oComputerNew.networkNew.PrepareData(ref xmlQueue) ; // This sets
  161. updaterequired in entity
  162.  
  163.                             if (oComputerNew.printerNew.PreparedXml != oComputerPrevious.
  164. printerNew.PreparedXml )
  165.                                 oComputerNew.printerNew.PrepareData(ref xmlQueue) ; // This sets
  166. updaterequired in entity
  167.  
  168.                             if (oComputerNew.shortcutNew.PreparedXml != oComputerPrevious.
  169. shortcutNew.PreparedXml )
  170.                                 oComputerNew.shortcutNew.PrepareData(ref xmlQueue) ; // This sets
  171. updaterequired in entity
  172.  
  173.                             if (oComputerNew.soeNew.PreparedXml != oComputerPrevious.soeNew.
  174. PreparedXml )
  175.                                 oComputerNew.soeNew.PrepareData(ref xmlQueue) ; // This sets
  176. updaterequired in entity
  177.  
  178.                             if (oComputerNew.softwareNew.PreparedXml != oComputerPrevious.
  179. softwareNew.PreparedXml )
  180.                                 oComputerNew.softwareNew.PrepareData(ref xmlQueue) ; // This sets
  181. updaterequired in entity
  182.  
  183.                             if (oComputerNew.usbNew.PreparedXml != oComputerPrevious.usbNew.
  184. PreparedXml )
  185.                                 oComputerNew.usbNew.PrepareData(ref xmlQueue) ; // This sets
  186. updaterequired in entity
  187.  
  188.                             #endregion
  189.  
  190.                             ComputerCurrent oComputerCurrent = new ComputerCurrent(oComputerNew);
  191.  
  192.                             if (oComputerCurrent.Compare())
  193.                             {
  194.                                 try
  195.                                 {
  196.                                     //Now update the Previous Data from the data queue object
  197.                                     oDataPrevious.INVData = oDataQueue.INVData ;
  198.                                     //Set the ID of the entity as the ComputerID
  199.                                     oDataPrevious.ID = oComputerCurrent.ID;
  200.                                     oDataPrevious.Insert();
  201.                                 }
  202.                                 catch
  203.                                 {
  204.                                     Status_Event(108,"Error : Could not update previous data") ;
  205.                                 }
  206.  
  207.                                 try
  208.                                 {
  209.                                     oDataQueue.Delete();
  210.                                 }
  211.                                 catch
  212.                                 {
  213.                                     Status_Event(101,"Error : Could not Delete DataQueue item") ;
  214.                                 }
  215.  
  216.                             }
  217.                             else
  218.                             {
  219.                                 try
  220.                                 {
  221.                                     oDataQueue.Failed();
  222.                                     Status_Event(102,"Error : Failed to process queue entry") ;
  223.                                 }
  224.                                 catch
  225.                                 {
  226.                                     Status_Event(103,"Error : Could not Mark DataQueue Failed") ;
  227.                                 }
  228.                             }
  229.  
  230.                         }
  231.                         else // error creating computernew. No exception AccountID set to 0
  232.                         {
  233.                             try
  234.                             {
  235.                                 oDataQueue.Failed();
  236.                                 Status_Event(105,"Error : XML - Could not create computer new object")
  237. ;
  238.                             }
  239.                             catch
  240.                             {
  241.                                 Status_Event(106,"Error : Could not Mark DataQueue Failed") ;
  242.                             }
  243.                         }
  244.  
  245.                     }
  246.                     catch
  247.                     {
  248.                         Status_Event(104,"Error : Could not create Computer New Object") ;
  249.                     }
  250.  
  251.                 }
  252.  
  253.             }
  254.             catch (Exception ex)
  255.             {
  256.                 Status_Event(100,"Error : Could not get next item in DataQueue") ;
  257.                 Status_Event(100,"Exception : " + ex.Message ) ;
  258.             }
  259.         }
  260.  
  261.         private void Status_Event(int code , string message)
  262.         {
  263.             int codeoffset = 2000 ;
  264.             code += codeoffset ;
  265.             eQueueProcess_Status.StatusCode = code ;
  266.             eQueueProcess_Status.StatusMessage = message ;
  267.             QueueProcess_Status_Event(this,eQueueProcess_Status) ;
  268.         }
  269.  
  270.         #endregion
  271.  
  272.         #region Properties
  273.  
  274.         public bool Stopped
  275.         {
  276.             get
  277.             {
  278.                 return stopped ;
  279.             }
  280.         }
  281.  
  282.         #endregion
  283.  
  284.         #region Event Classes and Delegates
  285.  
  286.         #region Status Event Class
  287.  
  288.         public delegate void QueueProcess_Status( object sender,
  289. QueueProcess_Status_EventArgs e) ;
  290.  
  291.         public class QueueProcess_Status_EventArgs : EventArgs
  292.         {
  293.             #region Private Variables
  294.  
  295.             private int statuscode ;
  296.             private string statusmessage ;
  297.  
  298.             #endregion
  299.  
  300.             #region Public Properties
  301.  
  302.             public int StatusCode 
  303.             {
  304.                 get { return statuscode ; }
  305.                 set { statuscode = value ; }
  306.             }
  307.  
  308.             public string StatusMessage 
  309.             {
  310.                 get { return statusmessage ; }
  311.                 set { statusmessage = value ; }
  312.             }
  313.  
  314.             #endregion
  315.         }
  316.  
  317.         #endregion
  318.  
  319.         #endregion
  320.  
  321.     }
  322. }
  323.  
Mar 16 '09 #1
Share this Question
Share on Google+
9 Replies


Expert 100+
P: 750
PRR
Firstly is this your service start function?
Expand|Select|Wrap|Line Numbers
  1. public void Start()
  2.          {
  3.              Status_Event(status_begin, "Queue Thread Begin") ;
  4.              stopped = false ;
  5.  
  6.              while (true)
  7.              {
  8.                  Thread.Sleep(100) ;
  9.                  Start_QueueProcess() ;
  10.                  if (stopped) break ;    
  11.              }
  12.              ....
  13.  
I don't see any timers being used... You can use system.timers.timer or threading timer for services...
You mentioned that you, "process files....form folder.. into database...further 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 )
Expand|Select|Wrap|Line Numbers
  1. while (true)
  2.              {
  3.                  Thread.Sleep(100) ;
  4.                  Start_QueueProcess() ;
  5.                  if (stopped) break ;    
  6.              }
  7.  
Possible solutions:
* If you intent to call Start_QueueProcess(), periodically you need to use system.timers.timer, 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 ...
Expand|Select|Wrap|Line Numbers
  1. GC.Collect();
  2. GC.WaitForPendingFinalizers();
  3. GC.Collect();
  4.  
* Write exception to a log file/ Event log
Mar 17 '09 #2

P: 4
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..
Mar 17 '09 #3

Expert 100+
P: 750
PRR
Could you post OnStart(), OnStop() code? I would suggest you replace
Expand|Select|Wrap|Line Numbers
  1.   while (true)
  2.               {
  3.                   Thread.Sleep(100) ;
  4.                   Start_QueueProcess() ;
  5.                   if (stopped) break ;    
  6.               }
  7.  
with
System.Timers.Timer

"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 ?
Mar 17 '09 #4

P: 4
Expand|Select|Wrap|Line Numbers
  1. protected override void OnStart(string[] args)
  2. {
  3. #region This code goes into service start
  4. oServiceLogger.Insert(1000,"DLS Start") ;
  5. XXX.ABCD.Dal.VersionDetails  oVersion = new XXX.ABCD.Dal.VersionDetails() ;
  6. oServiceLogger.Insert(1001,"DAL Version : " + oVersion.Get) ;
  7. #region QueueThread
  8. oQueueProcess = new QueueProcess() ;
  9. // Add event handler
  10. oQueueProcess.QueueProcess_Status_Event +=new XXX.ABCD.Dls.Queue.QueueProcess.QueueProcess_Status(oQueueProcess_QueueProcess_Status_Event);
  11. // Create and execute the thread
  12. Thread QueueThread = new Thread(new ThreadStart(oQueueProcess.Start )); 
  13. QueueThread.Start() ; //Thread start
  14. QueueThread = null ;
  15. #endregion
  16. #endregion
  17. }
  18.  
  19. protected override void OnStop()
  20. {
  21.     #region This code goes into service stop
  22.     Stop_Threads() ;
  23.     oServiceLogger.Insert(1999,"DLS Stop") ;
  24.     #endregion
  25. }
  26.  
  27. private void Stop_Threads()
  28. {
  29.     try
  30.     {
  31.         if (!oQueueProcess.Stopped) oQueueProcess.Stop() ; 
  32.     }
  33.     catch
  34.     {
  35.     }
  36. }
  37.  
  38. public void Stop()
  39. {
  40.     stopped = true ;
  41. }
  42.  
  43.  
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
Mar 17 '09 #5

Expert 100+
P: 750
PRR
Briefly i will explain certain things which may be useful..
1. System.Timers.Timer:
Expand|Select|Wrap|Line Numbers
  1. //Declare the timer 
  2. System.Timers.Timer myTimer = new System.Timers.Timer();
  3.  
  4. // initialize in service constructor...  
  5. myTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
  6.             myTimer.Interval = 5000;
  7.             myTimer.Enabled = true;
  8.  
As the code suggest declare a system.timers.timer and initialize it ...

Expand|Select|Wrap|Line Numbers
  1. static bool lockTimer = true;
  2.  
  3. private  void OnTimedEvent(object source, ElapsedEventArgs e)
  4.         {
  5.             if (true)
  6.             {
  7.                 lockTimer = false;
  8.                 CallFun2();
  9.  
  10.             }
  11.         }
  12.  
  13. public void CallFun2()
  14.         {
  15.             try
  16.             {
  17.                 //Do processing
  18.                 Console.WriteLine("Calling...");
  19.  
  20.             }
  21.             catch (Exception ex)
  22.             {
  23.                 //log exception
  24.             }
  25.             finally 
  26.             {
  27.                 lockTimer = true;
  28.                 //Unlock timer function
  29.             }
  30.         }
  31.  
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...
Mar 17 '09 #6

Expert 100+
P: 750
PRR
Any tasks that require short processing and can be independently executed can be done by using ThreadPool, such as writing to logs etc...
Expand|Select|Wrap|Line Numbers
  1. ThreadPool.QueueUserWorkItem(new WaitCallback(func1));
  2.  
  3. static void func1(Object o)
  4.         {            
  5.             Console.WriteLine("Thread Pool");
  6.         }
  7.  
Mar 17 '09 #7

Expert 100+
P: 750
PRR
Last but most important what ever you do, in your service do it as series of asynchronous tasks...Look into Asynchronous Programming Overview
Mar 17 '09 #8

P: 4
Hats off to you DeepBlue..

Thanks a lot for your time and suggestions...you Rock!!


Regards,
Mohith
Mar 17 '09 #9

Expert 100+
P: 750
PRR
Welcome... do continue to post your queries on Bytes
Mar 18 '09 #10

Post your reply

Sign in to post your reply or Sign up for a free account.