Как дождаться, пока консольное приложение не будет простаивать?

У меня есть консольное приложение, которое запускается, размещает кучу служб (длительный запуск), а затем ждет, когда клиенты вызовут его. У меня есть интеграционные тесты, которые запускают это консольное приложение и делают «клиентские» вызовы. Как дождаться завершения запуска консольного приложения, прежде чем совершать клиентские вызовы?

Я не хочу делать Thread.Sleep(int), потому что это зависит от времени запуска (которое может измениться), и я теряю время, если запуск происходит быстрее.

Process.WaitForInputIdle работает только с приложениями с пользовательским интерфейсом ( и я подтвердил, что в этом случае выдается исключение).

Я открыт для неудобных решений, таких как заставить консольное приложение записать временный файл, когда он будет готов.


person Anthony Mastrean    schedule 29.04.2010    source источник
comment
В консольном приложении размещаются службы WCF. Клиент выполняет вызовы WCF. Если консольное приложение не завершило запуск, клиент получает исключения Endpoint Not Found.   -  person Anthony Mastrean    schedule 29.04.2010


Ответы (5)


Один из вариантов — создать именованный EventWaitHandle. Это создает объект синхронизации, который можно использовать в процессах. Затем ваши «клиентские» приложения ждут, пока событие не будет сигнализировано, прежде чем продолжить. Как только основное консольное приложение завершило запуск, оно может сигнализировать об этом событии.

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

Например, ваше консольное приложение «Сервер» может иметь следующее. Это не скомпилировано, так что это просто отправная точка :)

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();
}

Затем клиенты будут делать что-то вроде этого

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 ...
}
person Chris Taylor    schedule 29.04.2010
comment
Что делает это имя? Я использовал имя MyCompany\HostStarted, и консольное приложение выдало исключение DirectoryNotFound! - person Anthony Mastrean; 30.04.2010
comment
Я должен был на самом деле упомянуть об этом. Префикс Global\ или Local\ управляет областью действия события. Global\ делает событие видимым во всех сеансах, а Local\ делает его видимым только в текущем сеансе. Это важное различие, когда приложение работает, например, в сеансе сервера терминалов, где вы можете использовать Local\ в зависимости от ваших требований. - person Chris Taylor; 30.04.2010
comment
это прекрасно и немного ужасно. я люблю это. - person nathan gonzalez; 24.09.2013
comment
Это круто! Благодарю. Я собирался реализовать целую трубу, чтобы отправить сигнал моему приложению о том, что сервер готов. - person Jack; 27.07.2016

Как насчет установки мьютекса и его удаления после завершения запуска. Пусть клиентское приложение подождет, пока оно не сможет захватить мьютекс, прежде чем оно начнет что-то делать.

person Malfist    schedule 29.04.2010
comment
В принципе аналогично ответу, который я предоставил, однако использование EventWaitHandle позволит нескольким клиентским приложениям синхронизироваться с основным приложением. - person Chris Taylor; 29.04.2010

Включите проверку готовности в клиентском интерфейсе приложения или сделайте так, чтобы оно возвращало ошибку «Не готово», если оно вызывается до того, как оно будет готово.

person Kyle Alons    schedule 29.04.2010
comment
Таким образом, приложение должно будет проверять цикл, пока оно не вернет ошибку «я не готов»? не уверен, что это хороший подход... - person Jack; 27.07.2016

Создайте службу WCF, которую можно использовать для запроса состояния серверного процесса. Запускайте эту службу только в том случае, если в командной строке передана конкретная команда. Следующие черты обеспечат очень быстрый запуск этой службы:

  • Разместите эту службу в качестве первой операции клиентского приложения.
  • Используйте привязку net.tcp или net.pipe, так как они запускаются очень быстро.
  • Сохраняйте эту службу как можно более простой, чтобы она оставалась доступной до тех пор, пока консольное приложение не завершит работу.

Средство выполнения тестов может попытаться подключиться к этой службе. Повторите попытку, если она не удалась, пока не завершится консольное приложение или не истечет достаточно короткий период ожидания. Пока консольное приложение не завершится неожиданно, вы можете положиться на эту службу, чтобы предоставить любую дополнительную информацию перед запуском тестов в течение достаточно короткого периода времени.

person Sam Harwell    schedule 29.04.2010
comment
Слишком много работы, мы размещаем эту штуку как сервис в производстве и никогда не сталкиваемся с такими проблемами с гонками. - person Anthony Mastrean; 29.04.2010

  • Поскольку два (консольное приложение и приложение для тестирования интеграции, которое делает клиентские вызовы, как я понимаю) являются отдельными приложениями, поэтому должен быть механизм - мост - который говорил бы играть в качестве посредника (сокет, внешний файл, реестр, так далее).

  • Другая возможность может заключаться в том, что вы вычисляете среднее время, необходимое консоли для загрузки служб, и используете это время в своем тестовом приложении; ну просто мысли вслух!

person KMån    schedule 29.04.2010