Служба зависает в WaitForExit после вызова командного файла - PullRequest
18 голосов
/ 12 декабря 2008

У меня есть служба, которая иногда вызывает командный файл. Пакетный файл занимает 5-10 секунд для выполнения:

System.Diagnostics.Process proc = new System.Diagnostics.Process(); // Declare New Process
    proc.StartInfo.FileName = fileName;
    proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
    proc.StartInfo.CreateNoWindow = true;
    proc.Start();
    proc.WaitForExit();

Файл существует, и код работает, когда я запускаю тот же код в консоли. Однако, когда он работает внутри службы, он зависает на WaitForExit(). Я должен убить командный файл из процесса, чтобы продолжить. (Я уверен, что файл существует, поскольку я вижу его в списке процессов.)

Как я могу исправить это зависание?

Обновление № 1:

Код Кевина позволяет мне получить вывод. Один из моих командных файлов все еще висит.

"C: \ EnterpriseDB \ Postgres \ 8.3 \ bin \ pg_dump.exe" -i -h localhost -p 5432 -U postgres -F p -a -D -v -f "c: \ backupcasecocher \ backupdateevent2008.sql "-t" \ "public \". \ "dateevent \" "" DbTest "

Другой пакетный файл:

"C: \ EnterpriseDB \ Postgres \ 8.3 \ bin \uumdb.exe" -U postgres -d DbTest

Я проверил путь, и путь postgresql в порядке. Выходной каталог существует и все еще работает за пределами службы. Есть идеи?

Обновление № 2:

Вместо пути к пакетному файлу я написал «C: \ EnterpriseDB \ Postgres \ 8.3 \ bin \ pg_dump.exe» для proc.StartInfo.FileName и добавил все параметры в proc.StartInfo.Arguments. Результаты не изменились, но я вижу pg_dump.exe в окне процесса. Опять же, это происходит только внутри сервиса.

Обновление № 3:

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

Обновление № 4:

Я создал простой сервис для записи трассировки в журнал событий и запуска командного файла, который содержит «dir». Теперь он будет зависать на proc.Start(); - я попытался изменить учетную запись с LocalSystem на Пользователь , и я установил пользователя и пароль администратора, но ничего не вышло.

Ответы [ 8 ]

29 голосов
/ 12 декабря 2008

Вот что я использую для выполнения командных файлов:

proc.StartInfo.FileName                 = target;
proc.StartInfo.RedirectStandardError    = true;
proc.StartInfo.RedirectStandardOutput   = true;
proc.StartInfo.UseShellExecute          = false;

proc.Start();

proc.WaitForExit
    (
        (timeout <= 0)
            ? int.MaxValue : timeout * NO_MILLISECONDS_IN_A_SECOND *
                NO_SECONDS_IN_A_MINUTE
    );

errorMessage = proc.StandardError.ReadToEnd();
proc.WaitForExit();

outputMessage = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();

Я не знаю, поможет ли это вам, но у меня нет проблемы с этим.

11 голосов
/ 07 января 2010
using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Diagnostics;
    namespace VG
    {
        class VGe
        {
            [STAThread]
            static void Main(string[] args)
            {
                Process proc = null;
                try
                {                
                    string targetDir = string.Format(@"D:\adapters\setup");//this is where mybatch.bat lies
                    proc = new Process();
                    proc.StartInfo.WorkingDirectory = targetDir;
                    proc.StartInfo.FileName = "mybatch.bat";
                    proc.StartInfo.Arguments = string.Format("10");//this is argument
                    proc.StartInfo.CreateNoWindow = false;
                    proc.Start();
                    proc.WaitForExit();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception Occurred :{0},{1}", ex.Message,ex.StackTrace.ToString());
                }
            }
        }
    }
4 голосов
/ 09 мая 2013
            string targetDir = string.Format(@"D:\");//PATH
            proc = new Process();
            proc.StartInfo.WorkingDirectory = targetDir;
            proc.StartInfo.FileName = "GetFiles.bat";
            proc.StartInfo.Arguments = string.Format("10");//argument
            proc.StartInfo.CreateNoWindow = false;
            proc.Start();
            proc.WaitForExit();

Проверено, работает ясно.

3 голосов
/ 12 декабря 2008

Следующий шаг, который я хотел бы сделать, - запустить отладчик и посмотреть, сможете ли вы сказать, что ожидает программа. Если у вас есть опыт отладки в сборке, вы можете получить ИДЕЮ того, что происходит, используя такие инструменты, как ProcExp, FileMon и т. Д.

Быть Windows SERVICE, а не веб-службой, имеет большое значение. В любом случае, вы попробовали мое предложение по настройке «Разрешить службе взаимодействовать с рабочим столом»?

Если вы в отчаянии, вы можете попробовать запустить cmd.exe вместо вашего командного файла. Затем, используя параметры строки cmd.exe cmd.exe, вы можете настроить IT на запуск командного файла. Это, вероятно, даст вам окно приглашения cmd для просмотра фактического вывода, если вы включите взаимодействие с рабочим столом.

Для полной справки по cmd.exe, просто наберите cmd /? в любой командной строке.

Larry

3 голосов
/ 12 декабря 2008

pg_dump.exe, вероятно, запрашивает ввод данных пользователем. Эта база данных требует аутентификации? Вы полагаетесь на какие-либо переменные ОКРУЖАЮЩЕЙ СРЕДЫ, которые не будут присутствовать для службы? Я не знаю pg_dump, но каковы другие возможные причины, по которым он запрашивает ввод?

3 голосов
/ 12 декабря 2008

Что делает пакетный файл? Вы уверены, что процесс запускается с достаточным количеством привилегированных пользователей для выполнения командного файла? Услуги могут быть ограничены в том, что им разрешено делать.

Также убедитесь, что вы делаете что-то вроде usin в команде копирования, чтобы перезаписать файл, который вы делаете что-то вроде:

echo Y | copy foo.log c:\backup\

Кроме того, убедитесь, что вы используете полные пути для пакетных команд и т. Д. Если пакетный файл запускает приложение с графическим интерфейсом в каком-то режиме «Консоль», это тоже может быть проблемой. Помните, что сервисы не имеют «рабочего стола» (если вы не включили «взаимодействие с рабочим столом»), чтобы рисовать любые окна или окна сообщений. В вашей программе вы можете захотеть открыть каналы stdout и stderr и читать их во время выполнения, если вы получаете какие-либо сообщения об ошибках или что-то подобное.

WebServices, вероятно, работают как учетная запись IUSR или как анонимная учетная запись, что когда-либо, так что это может быть проблемой для вас. Если он работает, когда вы запускаете его в консоли, это только первый шаг. :)

Я не помню, если System.Diagnostics. доступны только в отладочной или нет. Вероятно, нет, но некоторые из них могут быть. Я должен проверить это для тебя.

Надеюсь, это даст вам некоторые идеи.

Larry

1 голос
/ 16 декабря 2008

Даок, похоже, что единственное, что вы изменили, - это время ожидания первоначального WaitForExit (). Вы должны быть очень осторожны с этим. Если что-то ДЕЛАЕТ , повесит ваш сервис, он НИКОГДА не вернется (и, в общем-то, в значительной степени работает, как это было до сих пор ... хе), но это не будет хорошо для конечных пользователей .

Теперь, возможно, вы знаете, что вызывает зависание, вы можете отладить его дальше и найти полное решение ...

Это, или раскрутить это в каком-то потоке, который вы можете отслеживать, и убить, если он висит слишком долго.

Только мои 2 цента, что обычно не так много. ;)

1 голос
/ 13 декабря 2008

Вот решение. Решение не ясное, потому что я столько раз менял код, и теперь он работает!

Я пытался использовать учетную запись пользователя, и это не то, что сработало. Используйте LocalSystem. Вот код, который выполняется, в основном то, что дал мне Кевин.

            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo.FileName = fileName;
            proc.StartInfo.RedirectStandardError = true;
            proc.StartInfo.RedirectStandardOutput = true;
            proc.StartInfo.UseShellExecute = false;


            proc.Start();
            proc.WaitForExit();
            output1 = proc.StandardError.ReadToEnd();
            proc.WaitForExit();
            output2 = proc.StandardOutput.ReadToEnd();
            proc.WaitForExit();

Спасибо всем, я всех проголосую и приму Кевина, поскольку он помогает мне с самого начала. Очень странно, потому что это работает сейчас ...

...