web-dev-qa-db-fra.com

Le service raccroche à WaitForExit après avoir appelé le fichier de commandes

J'ai un service qui appelle parfois un fichier batch. Le fichier de commandes prend 5 à 10 secondes pour s'exécuter:

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

Le fichier existe et le code fonctionne lorsque j'exécute le même code dans la console. Cependant, lorsqu'il s'exécute à l'intérieur du service, il raccroche à WaitForExit(). Je dois tuer le fichier batch du processus afin de continuer. (Je suis certain que le fichier existe, comme je peux le voir dans la liste des processus.)

Comment puis-je résoudre ce problème?

Mise à jour n ° 1:

Le code de Kevin me permet d'obtenir une sortie. Un de mes fichiers batch est toujours suspendu.

"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"

L'autre fichier batch est:

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

J'ai vérifié le chemin et le chemin postgresql va bien. Le répertoire de sortie existe et fonctionne toujours en dehors du service. Des idées?

Mise à jour n ° 2:

Au lieu du chemin du fichier de commandes, j'ai écrit le "C:\EnterpriseDB\Postgres\8.3\bin\pg_dump.exe" pour le proc.StartInfo.FileName Et ajouté tous les paramètres à proc.StartInfo.Arguments. Les résultats sont inchangés, mais je vois le pg_dump.exe Dans la fenêtre de processus. Encore une fois, cela ne se produit qu'à l'intérieur du service.

Mise à jour n ° 3:

J'ai exécuté le service avec un utilisateur dans le groupe d'administrateurs, en vain. J'ai restauré null pour le nom d'utilisateur et le mot de passe du service

Mise à jour n ° 4:

J'ai créé un service simple pour écrire une trace dans le journal des événements et exécuter un fichier de commandes contenant "dir". Il va maintenant se bloquer à proc.Start(); - J'ai essayé de changer le compte de LocalSystem en ser et j'ai défini l'utilisateur et le mot de passe de l'administrateur, toujours rien.

18
Patrick Desjardins

Voici ce que j'utilise pour exécuter des fichiers batch:

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

Je ne sais pas si cela fera l'affaire pour vous, mais je n'ai pas le problème de le suspendre.

29
kemiller2002
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());
                }
            }
        }
    }
11
samir
            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();

Testé, fonctionne clairement.

4
suresh

pg_dump.exe demande probablement une entrée utilisateur. Cette base de données nécessite-t-elle une authentification? Vous fiez-vous à des variables ENVIRONNEMENT qui ne seront pas présentes pour le service? Je ne sais pas pg_dump mais quelles sont les autres raisons possibles pour lesquelles il demanderait une entrée?

3
Stephen Martin

Que fait le fichier batch? Êtes-vous certain que le processus est lancé avec suffisamment de privilèges pour exécuter le fichier de commandes? Les services peuvent être limités dans ce qu'ils sont autorisés à faire.

Assurez-vous également que si vous faites quelque chose comme utiliser la commande copy pour écraser un fichier, vous faites quelque chose comme:

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

Assurez-vous également que vous utilisez des chemins complets pour les commandes batch, etc. Si le fichier batch lance une application GUI dans une sorte de mode "Console", cela peut également être un problème. N'oubliez pas que les services n'ont pas de "Bureau" (sauf si vous activez l'option "Interagir avec le bureau") pour dessiner n'importe quel type de fenêtre ou de boîte de message. Dans votre programme, vous voudrez peut-être ouvrir les tubes stdout et stderr et les lire pendant l'exécution au cas où vous auriez des messages d'erreur ou quoi que ce soit.

Les WebServices s'exécutent probablement en tant que compte IUSR, ou compte anonyme, quel que soit le cas, cela peut donc être un problème pour vous. Si cela fonctionne lorsque vous l'exécutez dans la console, ce n'est que la première étape. :)

Je ne me souviens pas si System.Diagnostics. sont disponibles uniquement en débogage ou non. Probablement pas, mais certains d'entre eux pourraient l'être. Je vais devoir vérifier ça pour toi.

J'espère que cela vous donne quelques idées.

Larry

3
LarryF

La prochaine étape que je prendrais est de lancer le débogueur et de voir si vous pouvez dire ce que le programme attend. Si vous êtes expérimenté lors du débogage dans Assembly, vous pourrez peut-être obtenir un IDEA de ce qui se passe à l'aide d'outils tels que ProcExp, FileMon, etc.

Être un SERVICE Windows, et non un service Web, fait toute la différence. Quoi qu'il en soit, avez-vous essayé ma suggestion de définir le "Autoriser le service à interagir avec le bureau"?

Si vous êtes désespéré, vous pouvez essayer de lancer cmd.exe au lieu de votre fichier de commandes. Ensuite, en utilisant les paramètres de ligne cmd de cmd.exe, vous pouvez demander au service informatique de démarrer le fichier de commandes. Cela vous donnerait probablement une fenêtre d'invite cmd pour afficher la sortie réelle, si vous activez l'interaction avec le bureau.

Pour obtenir une aide complète sur cmd.exe, tapez simplement cmd /? à n'importe quelle invite de commande.

Larry

3
LarryF

Voici la solution. La solution n'est pas claire car j'ai changé tellement de fois le code et maintenant ça marche!

J'ai essayé d'utiliser un compte d'utilisateur, et ce n'est pas ce qui a fonctionné. Utilisez LocalSystem. Voici le code qui s'exécute, principalement ce que Kevin m'a donné.

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

Merci à tous, je voterai tout le monde et accepterai Kevin puisqu'il m'aide depuis le début. Très bizarre car ça marche maintenant ...

1
Patrick Desjardins

Daok, il semble que la seule chose que vous ayez modifiée était le délai d'expiration du WaitForExit () initial. Vous devez faire TRÈS attention à cela. Si quelque chose FAIT bloque votre service, il ne reviendra JAMAIS (et bien, à peu près comme cela a été pour vous jusqu'à présent .. heh), mais il ne sera pas bon pour les utilisateurs finaux ...

Maintenant, peut-être que vous savez ce qui cause ce blocage, vous pouvez le déboguer davantage et trouver la solution complète ...

Cela, ou faites-le tourner dans un thread que vous pouvez surveiller, et le tuer s'il se bloque trop longtemps.

Juste ma valeur de 2 cents, ce qui n'est généralement pas beaucoup. ;)

1
LarryF