Necesito escribir código robusto en .NET para permitir que un servicio de Windows (servidor 2003) se reinicie. ¿Cuál es la mejor manera de hacer esto? ¿Hay alguna API de .NET para hacerlo?
Necesito escribir código robusto en .NET para permitir que un servicio de Windows (servidor 2003) se reinicie. ¿Cuál es la mejor manera de hacer esto? ¿Hay alguna API de .NET para hacerlo?
Respuestas:
Configure el servicio para que se reinicie después de un error (haga doble clic en el servicio en el panel de control y eche un vistazo a esas pestañas; olvido el nombre). Luego, cada vez que desee que se reinicie el servicio, simplemente llame Environment.Exit(1)
(o cualquier devolución que no sea cero) y el sistema operativo lo reiniciará por usted.
Service.ExitCode = 1
y luego ejecutar Service.Stop()
junto con la casilla de verificación 'Habilitar acciones para paradas con errores' en la pantalla de configuración de recuperación del servicio. Hacerlo de esta manera permite un apagado adecuado y aún así activa el reinicio.
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()
No puede estar seguro de que la cuenta de usuario con la que se ejecuta su servicio tenga incluso permisos para detener y reiniciar el servicio.
Puede crear un proceso que sea un símbolo del sistema de DOS que se reinicie:
Process process = new Process();
process.StartInfo.FileName = "cmd";
process.StartInfo.Arguments = "/c net stop \"servicename\" & net start \"servicename\"";
process.Start();
const string strCmdText = "/C net stop \"SERVICENAME\"&net start \"SERVICENAME\"";
Process.Start("CMD.exe", strCmdText);
donde SERVICENAME
está el nombre de su servicio (las comillas dobles incluidas para dar cuenta de los espacios en el nombre del servicio, de lo contrario, se pueden omitir).
Limpio, no es necesaria la configuración de reinicio automático.
Dependerá de por qué quiere que se reinicie.
Si solo está buscando una manera de que el servicio se limpie periódicamente, entonces podría tener un temporizador ejecutándose en el servicio que periódicamente provoca una rutina de purga.
Si está buscando una forma de reiniciar en caso de falla, el host del servicio en sí mismo puede proporcionar esa capacidad cuando se configura.
Entonces, ¿por qué necesita reiniciar el servidor? ¿Qué estás intentando lograr?
No creo que pueda hacerlo en un servicio autónomo (cuando llama a Reiniciar, detendrá el servicio, lo que interrumpirá el comando Reiniciar, y nunca volverá a comenzar). Si puede agregar un segundo .exe (una aplicación de consola que usa la clase ServiceManager), puede iniciar el .exe independiente y hacer que reinicie el servicio y luego salga.
Pensándolo bien, probablemente podría hacer que el servicio registre una Tarea Programada (usando el comando 'at' de la línea de comandos, por ejemplo) para iniciar el servicio y luego hacer que se detenga; eso probablemente funcionaría.
El problema con el desplazamiento hacia 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 utilizar el método OnStop (), que es el punto de entrada para el Administrador de control de servicios. Luego, se ejecutará todo el código de limpieza y no tendrá ningún socket colgado u otros procesos, suponiendo que su código de detención esté haciendo su trabajo.
Para hacer esto, debe establecer un indicador antes de finalizar que le 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 SCM. Esto también supone 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 encuentra con un problema y necesita reiniciarse, inicio un subproceso que detiene el servicio desde el SCM. Esto permite que el servicio se 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) { }
}
Usaría el Programador de Windows para programar un reinicio de su servicio. El problema es que no puede reiniciarse, pero puede detenerse. (Esencialmente has cortado 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.
La primera respuesta a 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.
El mejor enfoque puede ser utilizar el Servicio NT como envoltorio para su aplicación. Cuando se inicia el Servicio NT, su aplicación puede iniciarse en un modo "inactivo" esperando que se inicie el comando (o configurarse para iniciarse automáticamente).
Piense en un automóvil, cuando se enciende 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.
Simplemente pasando: y pensé que agregaría información adicional ...
También puede lanzar una excepción, esto cerrará automáticamente el servicio de Windows, y las opciones de reinicio automático simplemente se activan. El único problema con esto es que si tiene un entorno de desarrollo en su PC, entonces el JIT intenta entrar en acción, y recibirá un mensaje que dice depurar S / N. diga no y luego se cerrará y luego se reiniciará correctamente. (en una PC sin JIT, todo funciona). La razón por la que estoy trolleando, es que este JIT es nuevo en Win 7 (solía funcionar bien con XP, etc.) y estoy tratando de encontrar una forma de deshabilitar el JIT ... Puedo probar el método Environment.Exit mencionado aquí, vea cómo Eso también funciona.
Kristian: Bristol, Reino Unido
Cree un archivo restart.bat como este
@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%
Luego elimine la tarea% taskname% cuando comience su% service%
Cree un dominio de aplicación separado para alojar el código de la aplicación. Cuando se requiere reiniciar, podríamos descargar y volver a cargar el dominio de aplicación en lugar del proceso (servicio de Windows). Así es como funciona el grupo de aplicaciones IIS, no ejecutan la aplicación asp.net directamente, usan appdmain por separado.
La forma más fácil es tener un archivo por lotes con:
parada neta inicio neto
y agregue el archivo al planificador con el intervalo de tiempo deseado
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();
}
}