2008-10-21 9 views
118

Necesito escribir un código robusto en .NET para permitir que un servicio de Windows (servidor 2003) se reinicie solo. ¿Cuál es la mejor manera de hacerlo? ¿Hay alguna API .NET para hacerlo?¿Cómo puede un servicio de Windows reiniciarse programáticamente?

+6

"Robusto" es una palabra de comadreja (https://stackoverflow.fogbugz.com/default.asp?W13086) - ¿Qué características específicas necesita? –

Respuesta

168

Establezca el servicio para reiniciar después de la falla (haga doble clic en el servicio en el panel de control y eche un vistazo a esas pestañas; se me olvida el nombre). Luego, cada vez que desee que el servicio se reinicie, simplemente llame al Environment.Exit(1) (o cualquier devolución distinta de cero) y el sistema operativo lo reiniciará por usted.

+0

Las soluciones simples son las mejores soluciones. Simplemente hice esto para reemplazar el "2º proceso existente para reiniciar periódicamente el primero". – geofftnz

+5

Fyi la ubicación está en el panel de servicios, haga clic con el botón derecho en el servicio en cuestión y seleccione propiedades, luego elija la pestaña de recuperación. –

+13

Veo cómo esto logra el comportamiento deseado, pero un código de retorno de 1 está destinado a decirle al sistema que hubo un error. ¿No es esta una mala práctica si no hubo ningún error y solo desea reiniciar su servicio? – mgttlinger

3

No creo que se pueda en un servicio autónomo (cuando llamas a Restart, detendrá el servicio, lo que interrumpirá el comando de reinicio, y no volverá a comenzar). Si puede agregar un segundo .exe (una aplicación de consola que utiliza la clase ServiceManager), puede iniciar el .exe independiente y hacer que reinicie el servicio y luego salir.

Pensándolo bien, probablemente puedas hacer que el servicio registre una tarea programada (usando el comando de línea de comando 'at', por ejemplo) para iniciar el servicio y luego hacer que se detenga; eso probablemente funcionaría.

1

No creo que pueda. Cuando un servicio se "detiene", se descarga por completo.

Bueno, de acuerdo, siempre hay una manera que supongo. Por ejemplo, puede crear un proceso separado para detener el servicio, luego reiniciarlo y luego salir.

13

No puede estar seguro de que la cuenta de usuario bajo la cual se ejecuta su servicio incluso tiene permisos para detener y reiniciar el servicio.

+0

Aunque hice +1-ed porque me enfrenté al mismo problema, al mirar sc.exe resulta que SERVICE_QUERY_CONFIG es dwDesiredAccess al llamar a OpenSCManager() y luego llama a OpenService() con SERVICE_START | SERVICE_STOP para abrir un servicio en particular y funciona bien (no hay problema con el acceso). No estoy seguro de cómo se puede hacer esto en .NET. – n0p

0

El mejor enfoque puede ser utilizar el servicio NT como un contenedor para su aplicación. Cuando se inicia el servicio NT, su aplicación puede iniciarse en modo "inactivo" esperando a que comience el comando (o se configure para que se inicie automáticamente).

Piense en un automóvil, cuando se inicia, comienza en un estado inactivo, esperando que su comando avance o retroceda. Esto también permite otros beneficios, como una mejor administración remota, ya que puede elegir cómo exponer su aplicación.

5

Dependerá del motivo por el que desea que se reinicie.

Si solo está buscando una forma de hacer que el servicio se limpie solo, entonces puede tener un temporizador ejecutándose en el servicio que ocasiona periódicamente una rutina de purga.

Si está buscando una forma de reiniciar en caso de falla, el host del servicio en sí puede proporcionar esa capacidad cuando se configura.

¿Por qué necesita reiniciar el servidor? ¿Qué estás intentando lograr?

+1

Esto no funcionaría si le preocupa el gran montón de objetos y la fragmentación de memoria. Supuestamente, los procesos .NET 4/4.5 y de 64 bits han ayudado mucho con esto. –

7

Se puede crear un proceso que es un símbolo del sistema DOS que se reinicia a sí mismo:

Process process = new Process(); 
process.StartInfo.FileName = "cmd"; 
process.StartInfo.Arguments = "/c net stop \"servicename\" & net start \"servicename\""; 
process.Start(); 
2

me gustaría utilizar el Programador de Windows para programar un reinicio de su servicio. El problema es que no puedes reiniciar tú mismo, pero puedes detenerte a ti mismo. (En esencia, cortaste la rama en la que estás sentado ... si entiendes mi analogía). Necesitas un proceso separado para hacerlo por ti. El Programador de Windows es apropiado. Programe una tarea única para reiniciar su servicio (incluso desde el propio servicio) para ejecutarlo de inmediato.

De lo contrario, tendrá que crear un proceso de "pastoreo" que lo haga por usted.

-2

La manera más fácil es tener un archivo por lotes con:

net stop net start

y agregar el archivo al programador con su intervalo de tiempo deseado

+0

No funciona porque el lote se detiene entre ambos comandos, porque es un proceso secundario del servicio en sí. –

-3
private static void RestartService(string serviceName) 
    { 
     using (var controller = new ServiceController(serviceName)) 
     { 
      controller.Stop(); 
      int counter = 0; 
      while (controller.Status != ServiceControllerStatus.Stopped) 
      { 
       Thread.Sleep(100); 
       controller.Refresh(); 
       counter++; 
       if (counter > 1000) 
       { 
        throw new System.TimeoutException(string.Format("Could not stop service: {0}", Constants.Series6Service.WindowsServiceName)); 
       } 
      } 

      controller.Start(); 
     } 
    } 
1

La primera respuesta la pregunta es la solución más simple: "Environment.Exit (1)" Estoy usando esto en Windows Server 2008 R2 y funciona perfectamente. El servicio se detiene solo, el O/S espera 1 minuto y luego lo reinicia.

+0

El tiempo de espera depende de cuánto tiempo lo configure para esperar. El valor predeterminado es 1 minuto sin embargo, pero si alguien no quiere que su respuesta dará la impresión equivocada. – Espen

22
Dim proc As New Process() 
Dim psi As New ProcessStartInfo() 

psi.CreateNoWindow = True 
psi.FileName = "cmd.exe" 
psi.Arguments = "/C net stop YOURSERVICENAMEHERE && net start YOURSERVICENAMEHERE" 
psi.LoadUserProfile = False 
psi.UseShellExecute = False 
psi.WindowStyle = ProcessWindowStyle.Hidden 
proc.StartInfo = psi 
proc.Start() 
+3

Recuerde agregar "" a su alrededor el nombre del servicio si contiene espacios. – apc

+2

Esto es solo para servicios que se ejecutan bajo una cuenta con privilegios, lo cual es una mala idea de todos modos. –

0

De paso, y pensaba que iba a añadir algo de información adicional ...

también puede lanzar una excepción, esta voluntad de auto cerrar el servicio de las ventanas, y las opciones de auto re-arranque solo entran en juego El único problema con esto es que si tienes un entorno de desarrollo en tu PC, entonces el JIT intenta activarte, y obtendrás un mensaje que indica que debes depurar Y/N. di no y luego se cerrará y luego volverá a comenzar correctamente. (en una PC sin JIT todo funciona). la razón por la que estoy trolling, este JIT es nuevo para Win 7 (solía funcionar bien con XP, etc.) y estoy tratando de encontrar una manera de deshabilitar el JIT ... puedo probar el método Environment.Exit mencionado aquí ver cómo eso funciona también

Kristian: Bristol, Reino Unido

+3

Todos estos lanzan soluciones de excepción, salida (1), todas evitan la limpieza adecuada de una aplicación. Salir sin gracia es una solución pobre – devshorts

8
const string strCmdText = "/C net stop \"SERVICENAME\"&net start \"SERVICENAME\""; 
Process.Start("CMD.exe", strCmdText); 

donde SERVICENAME es el nombre de su servicio (comillas dobles incluyó para dar cuenta de los espacios en el nombre del servicio, se puede omitir lo contrario).

Limpio, no es necesaria la configuración de reinicio automático.

+5

aprendido algo nuevo sobre & vs &&: [comando1] y [comando2] siempre ejecutará ambos comandos secuencialmente, mientras que [comando1] && [comando2] ejecutará command2 solo si command1 se ejecuta con éxito (http://www.autoitscript.com/forum/topic/54864-run-multiple-dos-commands-in-one-line/?p=415739) –

0

Crear un archivo Restart.bat como esto

@echo on 
set once="C:\Program Files\MyService\once.bat" 
set taskname=Restart_MyService 
set service=MyService 
echo rem %time% >%once% 
echo net stop %service% >>%once% 
echo net start %service% >>%once% 
echo del %once% >>%once% 

schtasks /create /ru "System" /tn %taskname% /tr '%once%' /sc onstart /F /V1 /Z 
schtasks /run /tn %taskname% 

A continuación, elimine la tarea% TaskName% cuando el servicio%% comienza

1

Crear un dominio de aplicación independiente para alojar el código de la aplicación. Cuando sea necesario reiniciar, podríamos descargar y volver a cargar el dominio de la aplicación en lugar del proceso (servicio de Windows). Así es como funciona el grupo de aplicaciones de IIS, no ejecutan la aplicación asp.net directamente, sino que usan appdmain por separado.

2

El problema con el bombardeo de un archivo por lotes o EXE es que un servicio puede tener o no los permisos necesarios para ejecutar la aplicación externa.

La forma más limpia de hacer esto que he encontrado es usar el método OnStop(), que es el punto de entrada para el Administrador de control de servicios. Luego se ejecutará todo su código de limpieza, y no tendrá ningún sockets colgantes u otros procesos, suponiendo que su código de detención está haciendo su trabajo.

Para hacer esto, debe establecer un indicador antes de terminar que indique al método OnStop que salga con un código de error; entonces, el SCM sabe que el servicio debe reiniciarse. Sin este indicador, no podrá detener el servicio manualmente desde el SCM. Esto también asume que ha configurado el servicio para reiniciar en caso de error.

Aquí está mi código de parada:

... 

bool ABORT; 

protected override void OnStop() 
{ 
    Logger.log("Stopping service"); 
    WorkThreadRun = false; 
    WorkThread.Join(); 
    Logger.stop(); 
    // if there was a problem, set an exit error code 
    // so the service manager will restart this 
    if(ABORT)Environment.Exit(1); 
} 

Si el servicio se ejecuta en un problema y debe reiniciarse, lanzo un hilo que se detiene el servicio del SMC.Esto permite que el servicio limpie después de sí mismo:

... 

if(NeedToRestart) 
{ 
    ABORT = true; 
    new Thread(RestartThread).Start(); 
} 

void RestartThread() 
{ 
    ServiceController sc = new ServiceController(ServiceName); 
    try 
    { 
     sc.Stop(); 
    } 
    catch (Exception) { } 
} 
0

nssm es bastante genial. Hará todo esto por usted

Cuestiones relacionadas