2009-03-27 8 views
5

Como parte de un gran proceso de automatización, estamos llamando a una API de terceros que realiza algunos servicios de llamadas de trabajo en otra máquina. Descubrimos recientemente que cada cierto tiempo, cuando la otra máquina no está disponible, la llamada API se desvía a veces hasta 40 minutos al intentar conectarse al servidor remoto.¿Un uso razonable de enhebrar en C#?

La API que estamos utilizando no ofrece una manera de especificar un tiempo de espera y no queremos que nuestro programa espere tanto tiempo, así que pensé que los hilos serían una buena forma de aplicar el tiempo de espera. El código resultante se ve algo como:

Thread _thread = new Thread(_caller.CallServices()); 

_thread.Start(); 
_thread.Join(timeout); 

if (_thread.IsAlive) 
{ 
     _thread.Abort(); 
     throw new Exception("Timed-out attempting to connect."); 
} 

Básicamente, quiero que APICall run(), pero si todavía se va después de que haya transcurrido el tiempo de espera, asuma que va a fracasar, matarlo y seguir adelante.

Ya que soy nuevo en el roscado en C# y en el tiempo de ejecución de .NET que pensé en dos preguntas relacionadas:

¿Existe un mecanismo mejor/más apropiado en las bibliotecas de .NET para lo que yo' Estoy tratando de hacer, y he cometido algún truco threading en ese pedazo de código?

Respuesta

5

Thread.Abort() es una solicitud para que se cancele el hilo y no garantiza que lo hará de manera oportuna. También se considera una mala práctica (lanzará una excepción de aborto de subprocesos en el subproceso cancelado, pero parece que la API de terceros no le ofrece otras opciones.

Si conoce (programáticamente) la dirección del host de servicio remoto usted debe hacer ping antes de transferir el control a la API de tercera parte.

Si no se utiliza un BackgroundWorker, podría configurar IsBackgroundThread del hilo de verdad, por lo que no mantiene su programa de terminación.

3

Mala idea. Thread.Abort no limpia necesariamente el lío que deja una llamada API tan interrumpida.

Si la llamada es cara, considere escribir un .exe por separado que realice la llamada, y pasar los argumentos a/desde la línea de comando o los archivos temporales. Puedes matar un .exe mucho más seguro que matar un hilo.

0

se podría funcionar, pero nadie podría decir con seguridad sin una comprensión de la API de terceros. Anular el hilo de esa manera podría dejar el componente en algún estado inválido que podría no ser abl e para recuperarse de, o tal vez no liberará los recursos que asignó (piense, ¿qué pasaría si una de sus rutinas simplemente dejara de ejecutarse a la mitad del camino? ¿Podría hacer alguna garantía sobre el estado en que se encontraría su programa?).

Como sugirió Cicil, podría ser una buena idea hacer ping al servidor primero.

3

También puede usar un delegado ... Crear un delegado para el método que hace el trabajo, luego invocar BeginInvoke en el delegado, pasarle los argumentos y una función de devolución de llamada para manejar los valores devueltos (si desea) ... Inmediatamente después de la BeginInvoke se puede esperar un tiempo designado para el delegado asynch a fin, y si no lo hace en ese tiempo especificado, pasar ...

public delegate [ReturnType] CallerServiceDelegate 
      ([parameter list for_caller.CallService]); 

    CallerServiceDelegate callSvcDel = _caller.CallService; 
    DateTime cutoffDate = DateTime.Now.AddSeconds(timeoutSeconds); 
    IAsyncResult aR = callSvcDel.BeginInvoke([here put parameters], 
              AsynchCallback, null); 
    while (!aR.IsCompleted && DateTime.Now < cutoffDate) 
     Thread.Sleep(500); 
    if (aR.IsCompleted) 
    { 
     ReturnType returnValue = callSvcDel.EndInvoke(aR); 
     // whatever else you need to do to handle success 
    } 
    else 
    { 
     callSvcDel.EndInvoke(aR); 
     // whatever you need to do to handle timeout 
    } 

NOTA: como está escrito AsynchCallback podía ser nulo, ya que el código recupera el valor de retorno de EndInvoke(), pero si lo desea, puede hacer que el método CallService() llame al delegado AsynchCallback y le pase los valores devueltos instalados ...

+0

¿Cómo manejas el tiempo de espera? ¿Simplemente dejas que el componente siga intentándolo durante hasta 40 minutos para conectarte al servidor que falta? Creo que la pregunta era cómo hacer que el componente deje de intentar conectarse. – Cybis

+0

Lo sentimos, fue la edición para agregar el código de muestra ... la fecha límite de espera es tratada por DateTime.Now

0

¿Su aplicación se ejecuta durante largos períodos de tiempo o es más una aplicación de ejecución según sea necesario? Si es el último, yo personalmente consideraría usar la opción Thread.Abort(). Si bien puede no ser el más deseable desde la perspectiva de un purista (gestión de recursos, etc.), es sencillo de implementar y puede pagar la factura dada la forma en que funciona su aplicación particular.

La idea de un ejecutable por separado tiene sentido. Quizás otra opción sea usar AppDomains. No soy un experto en esta área (doy la bienvenida a refinamientos/correcciones a esto), pero tal como lo entiendo, pondría la llamada de la API en una DLL separada y la cargaría en un Dominio de la aplicación por separado. Cuando finaliza la llamada API o tiene que cancelarla, puede descargar el AppDomain junto con la DLL. Este puede tiene el beneficio adicional de limpiar los recursos que un Thread.Abort directo() no ofrecerá.

Cuestiones relacionadas