Manejo de excepciones en un programa que necesita ejecutarse 24/7


14

He leído que solo debemos detectar las excepciones que se pueden manejar, lo que hace que la captura de la clase de excepción base (C # en este caso) sea una mala idea (además de otras razones). Actualmente soy parte de un proyecto en el que hasta ahora todavía no he visto nada más que la excepción base que se detecta. Mencioné que se considera una mala práctica hacerlo, pero la respuesta fue "Este servicio debe ejecutarse las 24 horas del día, los 7 días de la semana, así es como es".

Como no tuve una buena respuesta sobre cómo manejar adecuadamente las excepciones en un programa que necesita ejecutarse 24/7, ahora estoy aquí. No he logrado encontrar ninguna información / sugerencia sobre cómo lidiar con el manejo de excepciones en programas / servicios "críticos" que deben ejecutarse durante todo el día (y en este caso creo que puede estar bien si el servicio está inactivo por un minuto o dos, así que ni siquiera es crítico). Entiendo que depende de la naturaleza exacta del programa. Los requisitos para un programa que puede causar problemas que amenazan la vida son bastante diferentes en comparación con un escáner de registro para un juego en línea.

Dos ejemplos:

1: Un servicio de escritura anticipada para clientes de los ferrocarriles británicos, utilizado cuando buscan en línea estaciones de ferrocarril.

2: Un programa que controla automáticamente los interruptores ferroviarios para los ferrocarriles anteriores en función de la información en tiempo real proporcionada por varios sensores en las vías, trenes, etc.

El primer programa probablemente no causaría un problema importante si se cayera por un minuto o dos, mientras que el último podría causar bajas humanas. ¿Sugerencias sobre cómo lidiar con cada uno? ¿Apunta a dónde puedo encontrar más información y pensamientos sobre este tema?


2
El desbobinado de la pila durante el manejo de excepciones en una aplicación en tiempo real (sic!) Puede destruir un tren.
Deer Hunter

44
@DeerHunter La codificación incorrecta, sin excepciones, puede tener el mismo resultado.
B 22овић

99
Ok, entonces tu catch Exception. Eso no significa que su programa funcione , significa que las fallas permiten que el estado de la aplicación se corrompa mientras continúa ejecutándose, un lugar mucho más peligroso. Un estrelló programa podría ser desastroso, pero un programa que está en un estado no válido, pero todavía puede ser acciones que realizan activamente desastrosa.
Phoshi

1
Si la aplicación necesita ejecutarse las 24 horas del día, los 7 días de la semana, hay un bucle infinito en algún lugar y es mejor que este bucle infinito se envuelva alrededor de alguna construcción que capture todas las excepciones no controladas. Si ese no es el caso, una excepción no controlada se filtrará al controlador global ya existente que está fuera de main, y kaboom! la aplicación 24/7 termina.
David Hammen

Respuestas:


7

Ciertas características del lenguaje como

  • Recolección de basura
  • Sistemas de excepción
  • Evaluación perezosa

generalmente no son útiles en un sistema en tiempo real. Probablemente deberíamos elegir un idioma sin estas características e intentar probar ciertas propiedades como el uso máximo de memoria o el tiempo de respuesta máximo.


Cuando un programa necesita ejecutarse continuamente, pero las fallas cortas y no globales son aceptables, entonces podríamos usar una estrategia similar a Erlang. Erlang es un lenguaje de programación concurrente y funcional. Por lo general, un programa escrito en Erlang consistirá en múltiples procesos de trabajo que pueden comunicarse entre sí (modelo de actor). Si un subproceso de trabajo encuentra una excepción, se reinicia. Si bien esto implica un breve tiempo de inactividad, los otros actores pueden continuar como de costumbre.

Para resumir esto: en un programa robusto, varias partes están aisladas unas de otras y se pueden reiniciar o escalar de forma independiente.

Entonces, básicamente, necesitamos un código equivalente a esto:

while (true) {
  try {
    DoWork();
  }
  catch (Exception e) {
    log(e);
  }
}

más una forma de terminar el ciclo. Tal bucle conduciría cada hilo de trabajo.


Un problema al ignorar los errores a través de un problema general es que los invariantes de su programa podrían haber sido violados por la causa del error, y que las operaciones posteriores podrían ser inútiles. Una buena solución para esto es no compartir datos entre trabajadores independientes. Reiniciar un trabajador reconstruirá todos los invariantes necesarios. Esto significa que deben comunicarse de manera diferente, por ejemplo, mediante el envío de mensajes. El estado de un actor puede no ser parte de las invariantes de otros actores.

Otro problema con la captura de demasiadas excepciones es que no todas las excepciones se pueden solucionar reiniciando, incluso cuando se toman esas precauciones. De lo contrario, los problemas difíciles como quedarse sin memoria se pueden manejar reiniciando. Pero un reinicio no lo ayudará a recuperar la conectividad a Internet cuando se desconectó un cable físico.


1
Sí, pero la situación como "se desconectó un cable físico" es exactamente cuando solo desea que el registro de excepciones se llene hasta que alguien vuelva a enchufar el cable, luego las cosas comienzan a funcionar nuevamente, sin un reinicio manual adicional de la aplicación.
Mark Hurd el

2

Para responder a su pregunta, uno tiene que entender qué son las excepciones y cómo funcionan.

Por lo general, se producen excepciones cuando se producen dichos errores, donde se requiere la asistencia del usuario. En tales casos, no importa cuánto tiempo lleve desenrollar la pila y manejar la excepción.

Sin controladores de captura, el programa detiene la ejecución. Dependiendo de su configuración y requisitos, puede ser aceptable.

En tus casos específicos:

  1. Si la consulta no se puede ejecutar (por ejemplo, nombre de ciudad incorrecto), informe al usuario del error y solicite que lo corrija.
  2. Si no obtiene información de un sensor crítico, no tiene mucho sentido continuar sin pedirle al operador que solucione el problema.

Eso significa que en ambos casos puede tener sentido usar excepciones, con más cuidado en un programa de RT para indicar solo problemas serios donde no es posible continuar la ejecución.


1

Hasta ahora todavía no he visto nada más que la excepción base que se detecta.

Parece que hay un problema aquí, en la medida en que las excepciones no se tratan adecuadamente. Capturar excepciones en el punto apropiado y tomar las medidas apropiadas (dependiendo del tipo de excepción) mantendrá el servicio funcionando de una manera mucho más confiable.

Si el servicio debe continuar, presumiblemente es importante que funcione según lo previsto. Dado su ejemplo, si un programa que controla los interruptores ferroviarios arroja una excepción, puede indicar que hay un problema para comunicarse con los sensores relacionados con la seguridad. Si detecta la excepción base y continúa, el servicio puede ejecutarse, pero puede no funcionar como se esperaba y provocar un desastre.

Alternativamente, si detecta la excepción lanzada cuando hay una falla de comunicación con el sensor y la trata adecuadamente (es decir, detener los trenes en el área afectada), su servicio se está ejecutando y no ha matado a nadie.

Entonces, como entiendo la pregunta, sugeriría que, en primera instancia, sería mejor agregar un manejo de excepciones más específico en lugar de eliminar los manejadores de tipo base-excepción.


0

Con respecto al punto 2: no use C #. No es un lenguaje en tiempo real y que va a hacerse daño si se intenta utilizar como tal.

Para el punto 1: podría seguir el camino erlang: dejar que se bloquee, luego reiniciar


Mi uso y experiencia en C # no están relacionados con el punto 2 (cambio de pista en tiempo real). Tengo curiosidad por qué C # es tan inadecuado para tal tarea?
Michael O'Neill

1
Principalmente: el recolector de basura hace que el comportamiento del programa, con respecto al tiempo, sea impredecible. Además, el tiempo de ejecución es demasiado complejo, y en esos contextos necesita cosas simples, son más predecibles
miniBill

0

Declaimer: estos son solo pensamientos, no tengo la experiencia.

Supongo que un programa que satisfaga los requisitos del segundo ejemplo debería ser extremadamente modular . En consecuencia, los módulos podrán reiniciarse sin desestabilizar el sistema.

Por ejemplo, un objeto, al fallar una afirmación de estado interno, debería poder destruirse y volver a crearse, notificando en el proceso a todos sus consumidores y proveedores. Más concretamente, si el programa está controlando los interruptores del ferrocarril y falla una afirmación en el bucle de decisión, aún puede ejecutar un módulo de emergencia, que detiene todos los trenes involucrados y espera a que el módulo de decisión principal se reinicialice.

Más realista, uno introduciría redundancia : duplicación del hardware y software. Una instancia está conectada al sistema controlado y la otra es de ejecución libre. Si se detecta un error, los sistemas se conmutan.

Un ejemplo son dos procesos en la misma máquina, que se monitorean uno al otro y si uno se mata, el otro lo vuelve a generar y disocia su PID padre de sí mismo.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.