8

I have a console application that starts up, hosts a bunch of services (long-running startup), and then waits for clients to call into it. I have integration tests that start this console application and make "client" calls. How do I wait for the console application to complete its startup before making the client calls?

I want to avoid doing Thread.Sleep(int) because that's dependent on the startup time (which may change) and I waste time if the startup is faster.

Process.WaitForInputIdle works only on applications with a UI (and I confirmed that it does throw an exception in this case).

I'm open to awkward solutions like, have the console application write a temp file when it's ready.

Anthony Mastrean
  • 21,850
  • 21
  • 110
  • 188
  • The console application hosts WCF services. The "client" makes WCF calls. If the console application has not completed startup, the client gets Endpoint Not Found exceptions. – Anthony Mastrean Apr 29 '10 at 19:18

5 Answers5

10

One option would be to create a named EventWaitHandle. This creates a synchronization object that you can use across processes. Then you have your 'client' applications wait until the event is signalled before proceeding. Once the main console application has completed the startup it can signal the event.

http://msdn.microsoft.com/en-us/library/41acw8ct(VS.80).aspx

As an example, your "Server" console application might have the following. This is not compiled so it is just a starting point :)

using System.Threading;
static EventWaitHandle _startedEvent;
static void main()
{  
  _startedEvent = new EventWaitHandle(false, EventResetMode.ManualReset, @"Global\ConServerStarted");

  DoLongRunnningInitialization();

  // Signal the event so that all the waiting clients can proceed
  _startedEvent.Set();
}

The clients would then be doing something like this

using System.Threading;
static void main()
{  
  EventWaitHandle startedEvent = new EventWaitHandle(false, EventResetMode.ManualReset, @"Global\ConServerStarted");

  // Wait for the event to be signaled, if it is already signalled then this will fall throught immediately.
  startedEvent.WaitOne();    

//  ... continue communicating with the server console app now ...
}
Chris Taylor
  • 52,623
  • 10
  • 78
  • 89
  • 2
    What does that name "do"? I used the name "MyCompany\HostStarted" and the console application threw a DirectoryNotFound exception! – Anthony Mastrean Apr 29 '10 at 20:17
  • 3
    I should have actually mentioned that. The Global\ or Local\ prefix controls the scope of the event. Global\ makes the event "visibile" across all sessions, while Local\ will make the it only visible in the current session. This is important distinction when the app is running on a terminal server session for example, where you might want the use Local\ depending on your requirements. – Chris Taylor Apr 29 '10 at 20:17
  • 1
    this is awesome and kind of terrible. i love it. – nathan gonzalez Sep 24 '13 at 19:35
  • This is awesome! thanks. I was considering to do a whole pipe implemention just to send a signal to my application that the "server" was ready – Jack Jul 27 '16 at 17:09
4

What about setting a mutex, and removing it once start up is done. Have the client app wait until it can grab the mutex before it starts doing things.

Malfist
  • 31,179
  • 61
  • 182
  • 269
  • Similar in principal to the answer I have provided, however using a EventWaitHandle will allow multiple client apps to sync on the main app. – Chris Taylor Apr 29 '10 at 19:19
1

Include an is ready check in the app's client interface, or have it return a not ready error if called before it's ready.

Kyle Alons
  • 6,955
  • 2
  • 33
  • 28
  • So the application would need to check in loop until it doesn't return a "i'm not ready error"? not sure if it's a good approach... – Jack Jul 27 '16 at 17:19
1

Create a WCF service that you can use for querying the status of the server process. Only start this service if a particular command is passed on the command line. The following traits will ensure a very fast startup of this service:

  • Host this service as the first operation of the client application
  • Use the net.tcp or net.pipe binding because they start very quickly
  • Keep this service as simple as possible to ensure that as long as the console application doesn't terminate, it will remain available

The test runner can attempt to connect to this service. Retry the attempt if it fails until the console application terminates or a reasonably short timeout period expires. As long as the console application doesn't terminate unexpectedly you can rely on this service to provide any additional information before starting your tests in a reasonably short period of time.

Sam Harwell
  • 97,721
  • 20
  • 209
  • 280
0
  • Since the two(the console application, and integration test app that makes client calls - as I understand) are separate application, so there should be a mechanism - a bridge - that would tell play as a mediator(socket, external file, registry, etc).

  • Another possibility could be that you come up with an average time the console takes to load the services and use that time in your test app; well, just thinking out loud!

KMån
  • 9,896
  • 2
  • 31
  • 41