none
Wait for child process to start RRS feed

  • Question

  • Hello,

    I have a Windows Service and I want to run a child process from within this Windows Service. I am using C# Process class and its StartInfo property to start the process. 

    However, it is not sure to me whether the child process is initialized and started successfully. So, I want to wait until the child process has been started successfully. FYI, the child process is a small server with no UI.

    I don't want to use Thread.Sleep(). My child process do not have any UI. So, as per the documentation, I can not use WaitForInputIdle method. I also tried to use ManagementEventWatcher, but parent process [Windows Service] does not wait for child process because http request is being sent before the child process is started.

    Here is my code to start the child process:

            public void startReqtifyInstance()
            {
                //Read port number from INI file                        
                int delayBeforeClosing = INIFileHandler.IniReadValue("ExternalServer", "DelayBeforeClosing");
                setPortNo(DataHelper.getPortNumberForNewReqtifyInstance());
                                                   
                Process proc = new Process();
                proc.StartInfo.UseShellExecute = false;
                proc.StartInfo.FileName = DataHelper.getReqtifyPath();
                proc.StartInfo.Arguments = "-http " + portNo + " -timeout " + DataHelper.getDelayBeforeClosingSession()
                +" -logfile " + @ServerConfig.LOG_FILE_PATH;
                proc.StartInfo.CreateNoWindow = true;
                proc.StartInfo.RedirectStandardOutput = true;
                proc.StartInfo.RedirectStandardError = true;
    
                try
                {
                    var queryString =
                   "SELECT TargetInstance " +
                   "FROM __InstanceCreationEvent WITHIN 1 " +
                   "WHERE TargetInstance ISA 'Win32_Process' " +
                   "AND TargetInstance.Name LIKE 'reqtify.exe'";
    
                    var scope = @"\\.\root\CIMV2";
    
                    var watcher = new ManagementEventWatcher(scope, queryString);                
                    watcher.EventArrived += (sender, e) => watcher_EventArrived(sender, e, proc.Id);
    
                    watcher.Start();
    
                    proc.Start();                
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error {0}", e.ToString());
                }
            }
    
            void watcher_EventArrived(object sender, EventArrivedEventArgs e,int processId)
            {
                Console.WriteLine("Reqtify has been started");
                setReqtifyProcessId(processId);
            }

    I hope you understand the code.

    Please give me some advice on this or any other elegant solution. 

    Thank you in advance!

    Navnath


    • Edited by NavnathK Monday, August 6, 2018 10:17 AM
    Monday, August 6, 2018 10:08 AM

Answers

  • There isn't any way to know when the request is going to be accepted. Your only option is to poll. You'll have to keep sending requests until it finally accepts it or you've waited long enough. If you know it takes at least 5 seconds then putting in a sleep first would be a good option (or a Task.Delay). Then go into a loop trying to send the request until either you've tried enough times or it succeeds. This is generally referred to as a spin wait. After each attempt you should probably stall for a fixed amount of time and then try again. Otherwise you'll potentially slow down the startup process even more.

    An alternative approach, if you own both processes, is to have your HTTP server set a global object. Then your client process can keep trying to acquire the object until it succeeds. This works well on a local machine but wouldn't work if the client/server are on separate machines so if you intend to separate them at some point then don't go this route.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by NavnathK Friday, August 10, 2018 10:38 AM
    Monday, August 6, 2018 3:54 PM
    Moderator

All replies

  • Well, the process is started, but it may take it time before it can service your requests. The only way to monitor it is to query it. Either it has defined methods to do this or not. In the second case, you need to resend your request when it fails, assuming that the process is still in its internal starting phase.

    Monday, August 6, 2018 12:17 PM
  • Does this suit for your situation:

    Process.WaitForExit Method ()

     Instructs the Process component to wait indefinitely for the associated process to exit. They may first complete the process then the further code execution proceed.



    -Niranjan Kala http://www.niranjankala.in

    Monday, August 6, 2018 1:50 PM
  • Hello Niranjan,

    Process.WaitForExit Method () waits for process to exit. I do not want to wait this much time. I want to wait until the process is properly initialized and started.

    Monday, August 6, 2018 2:09 PM
  • I think there is nothing to determine if application is started. In windows service there is information returned by Start method. But application is started by entry point and OS doesn't have any feedback.
    Monday, August 6, 2018 2:18 PM
  • What do you mean by "application is started by entry point and OS doesn't have any feedback" ?

    Monday, August 6, 2018 2:20 PM
  • "However, it is not sure to me whether the child process is initialized and started successfully. "

    What do you mean by that? At what point do you consider a process started and initialized? For a process like Notepad it would be initialized almost immediately but a process like Visual Studio would take a lot longer. It is completely dependent upon the process in question.

    In general, if Process.Start returns back successfully then the process has been "started" but may not be fully initialized yet. It is completely dependent upon the scheduler, the process startup code and what else is going on in the system. Once you have the Process object you can always query for whether it exited or not. However if the creation fails (bad filename, etc) then you'll get an exception. Once the process starts you can check the exit code to see if it has already completed but unless the process returns an exit code then you won't have any way of knowing whether it terminated successfully or not.

    Part of your solution will also depend upon how your service interacts with the process. Can your service shut down before the process ends? If so then there is no relation and so checking for anything beyond the process starting doesn't make sense. If however your service will wait until the process completes then it is just easier to block until the process terminates (perhaps in a separate thread) or use the Exited event to get notified when it does complete. 

    For a console app you can also capture output and error stream (if used) messages by using their events as well. But this doesn't really relate to initialization of the process.



    Michael Taylor http://www.michaeltaylorp3.net

    Monday, August 6, 2018 2:53 PM
    Moderator
  • >>"However, it is not sure to me whether the child process is initialized and started successfully. "

    >>What do you mean by that? At what point do you consider a process started and initialized?

    As I mentioned in my problem description, the child process that I want to wait for is a small server.

    So, I consider this process started and initialized at a point where my http request is handled by that server process. Its giving me "Unable to connect to the server" error because the request is sent before the server process is fully initialized.  That is why I want to wait for the server process to be completely initialized.

    Monday, August 6, 2018 3:03 PM
  • There isn't any way to know when the request is going to be accepted. Your only option is to poll. You'll have to keep sending requests until it finally accepts it or you've waited long enough. If you know it takes at least 5 seconds then putting in a sleep first would be a good option (or a Task.Delay). Then go into a loop trying to send the request until either you've tried enough times or it succeeds. This is generally referred to as a spin wait. After each attempt you should probably stall for a fixed amount of time and then try again. Otherwise you'll potentially slow down the startup process even more.

    An alternative approach, if you own both processes, is to have your HTTP server set a global object. Then your client process can keep trying to acquire the object until it succeeds. This works well on a local machine but wouldn't work if the client/server are on separate machines so if you intend to separate them at some point then don't go this route.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by NavnathK Friday, August 10, 2018 10:38 AM
    Monday, August 6, 2018 3:54 PM
    Moderator
  • You are redirecting standard output. Would it work to respond to data from standard output? Do you get data from standard output from the application prior to (at) the point that you need do something with it?

    See How to detect lunch or closing process ?. That does not actually ask about lunch. It might help.

    Another possibility might be to use the __InstanceCreationEvent event of the WMI Win32_Process class.



    Sam Hobbs
    SimpleSamples.Info

    Monday, August 6, 2018 7:24 PM