2010-05-03 22 views
5

Actualmente estoy trabajando en una aplicación de servidor si hemos acordado intentar y mantener un cierto nivel de servicio. El nivel de servicio que queremos garantizar es: si el servidor acepta una solicitud y el servidor envía un acuse de recibo al cliente, queremos garantizar que la solicitud se realice, incluso si el servidor falla. Como las solicitudes pueden ser de larga duración y el tiempo de acuse de recibo debe ser breve, lo implementamos persistiendo en la solicitud, enviando un acuse de recibo al cliente y luego llevando a cabo las diversas acciones para cumplir con la solicitud. A medida que se llevan a cabo las acciones, también se mantienen, por lo que el servidor conoce el estado de una solicitud al inicio, y también hay varios mecanismos de reconciliación con sistemas externos para verificar la precisión de nuestros registros.Prueba de código tolerante a errores

Todo parece funcionar bastante bien, pero tenemos dificultades para decirlo con convicción, ya que nos resulta muy difícil probar nuestro código tolerante a errores. Hasta aquí hemos llegado con dos estrategias pero tampoco es del todo satisfactoria:

  • Tener un proceso externo ver el código del servidor y luego tratar de acabar con él en lo que piensa el proceso externo es un punto apropiado de la prueba
  • Añadir un código de la aplicación que va a hacer que se caiga una determinada saben puntos críticos

Mi problema con la primera estrategia es el proceso externo no puede conocer el estado exacto de la aplicación, por lo que no puede estar seguro de que' Estoy golpeando los puntos más problemáticos en el código. Mi problema con la segunda estrategia, aunque da más control sobre las fallas, es que no me gusta tener código para inyectar fallas dentro de mi aplicación, incluso con compilación opcional, etc. Temo que sería demasiado fácil pasar por alto una falla punto de inyección y hacer que se deslice en un entorno de producción.

Respuesta

3

Creo que hay tres formas de lidiar con esto, si está disponible, podría sugerir un conjunto completo de pruebas de integración para estos diversos códigos, utilizando inyección de dependencia u objetos de fábrica para producir acciones interrumpidas durante estas integraciones.

En segundo lugar, ejecutar la aplicación con kill -9 aleatorio y deshabilitar las interfaces de red puede ser una buena manera de probar estas cosas.

También sugeriría probar la falla del sistema de archivos. Cómo lo haría depende de su sistema operativo, en Solaris o FreeBSD. Crearía un sistema de archivos zfs en un archivo y luego registraría el archivo mientras la aplicación se está ejecutando.

Si está utilizando el código de la base de datos, entonces sugeriría probar la falla de la base de datos también.

Otra alternativa a la inyección de dependencia, y probablemente la solución que utilizaría, son los interceptores, puede habilitar interceptores de prueba de bloqueo en su código, estos conocerían el estado de la aplicación e introducirían los fallos enumerados anteriormente en el momento correcto, o cualquier otro que desee crear. No requeriría cambios a su código existente, solo un código adicional para envolverlo.

+0

¿Dónde puedo encontrar más información sobre "interceptores de prueba de choque" en la plataforma .NET? Aunque usamos DI para pruebas unitarias, no creo que funcione demasiado bien para las pruebas de integración. Hay dos razones para esto: primero queremos que las pruebas de integración estén lo más cerca posible del código que se ejecutará en producción y, en segundo lugar, exigir que el código inyectado cause la falla tendría un impacto significativo (e indeseable) en cómo diseñamos los diversos módulos de la aplicación. – Robert

+0

Hola Robert, hay algunas buenas lecturas aquí http://www.sharpcrafters.com/aop.net/runtime-weaving – Justin

+0

También un buen ejemplo usando Spring.NET http://www.developer.com/net/csharp/ article.php/3795031/Aspect-Oriented-Programming-AOP-with-SpringNet.htm – Justin

2

Una posible respuesta al primer punto es multiplicar los experimentos con su proceso externo para que la probabilidad de afectar las partes problemáticas del código aumente. Luego puede analizar el archivo de volcado del núcleo para determinar dónde se ha bloqueado realmente el código.

Otra forma es aumentar la observabilidad y/o la capacidad de comando anulando las llamadas de biblioteca o kernel, es decir, sin modificar el código de la aplicación.

se pueden encontrar algunos recursos en Fault Injection página de Wikipedia, en particular en software implementado inyección de fallos sección.

1

Estaba a punto de escribir la misma que Justin :)

El componente que sugeriría para reemplazar durante la prueba podría ser el componente de registro (si tiene uno, si no, me gustaría sugerir fuertemente para poner en práctica uno...). Es relativamente fácil reemplazarlo con código que genera errores y el registrador generalmente obtiene suficiente información para conocer el estado actual de la aplicación.

También parece factible garantizar que el código de prueba no entre en producción. Sin embargo, desalentaría la compilación condicional, sino que iría con algún archivo de configuración para seleccionar el componente de registro.

El uso de muertes "fortuitas" puede ayudar a detectar errores, pero no es adecuado para las pruebas sistemáticas debido a su carácter no determinista. Por lo tanto, no lo usaría para las pruebas automáticas.

+0

Hacer que el registrador sea responsable de inyectar las fallas es una idea interesante, y algo que simplemente no se me había ocurrido. Definitivamente lo daré hace. – Robert

2

Su preocupación por la inyección de fallas no es una preocupación fundamental. Simplemente necesita una forma infalible de evitar que dicho código termine en la implementación. Una forma de hacerlo es mediante el diseño de su inyector de fallas como un depurador. Es decir. las fallas son inyectadas por un proceso externo a su proceso. Esto ya proporciona un nivel de aislamiento. Además, la mayoría de los sistemas operativos proporcionan algún tipo de control de acceso que evita la depuración a menos que esté habilitado específicamente. En la forma más primitiva, es limitándolo a root, en otros sistemas operativos requiere un "privilegio de depuración" específico. Naturalmente, en la producción nadie tendrá eso, y por lo tanto su inyector de fallas ni siquiera puede funcionar en producción.

En la práctica, el inyector de fallas puede establecer puntos de interrupción en direcciones específicas, es decir, función o incluso línea de código. Entonces puede reaccionar a eso, p. al finalizar el proceso después de que un determinado punto de interrupción se golpea tres veces.

+0

Su derecho a que las inyecciones de fallas se filtren en la producción puede o no ser un problema dependiendo de la implementación de la inyección de falla. Implementar la inyección de fallas a través de un depurador es ciertamente un enfoque interesante. Parece que al menos hay una extensión para windbg que le permitiría hacer esto (http://www.woodmann.com/collaborative/tools/index.php/PyDbgEng). ¿Hay algún otro enfoque que funcione bien en el entorno Windows/.NET? – Robert

Cuestiones relacionadas