Manejo de errores y comentarios Al realizar operaciones a granel en una arquitectura de múltiples niveles

StackOverflow https://stackoverflow.com/questions/1340062

Pregunta

Supongamos que tiene un método de lógica comercial que puede realizar alguna operación en varios objetos. Tal vez desee llamar a un servicio web de selección de número de lotería, una vez para cada persona seleccionada de una lista. En Java, el código podría verse algo así:

Set<Person> selectedPeople = ... // fetch list of people
for ( Person person : selectedPeople ) {
    String lotteryNumber = callLotteryNumberWebService( person );
    // ...
}

Tenga en cuenta que el servicio web del número de lotería puede tener efectos secundarios, como registrar que la persona ha solicitado un número de lotería (tal vez cobrar su cuenta), por lo que incluso si la llamada del servicio web falla para una persona, puede haber tenido éxito para otros. Esta información (los números de lotería) deberá ser devuelto a algún nivel superior (la vista).

Si este fuera un caso en el que tuvo lugar una sola operación, el método de lógica comercial podría devolver un valor único (por ejemplo, el número de lotería) o lanzar una excepción con cualquier detalle de la falla. Pero para las operaciones a granel, sería posible que algunas de las operaciones tengan éxito y algunas fallaran.

Esto parece un tipo de problema que ocurriría en muchas aplicaciones y debería haber una forma limpia de manejarlo. Entonces, ¿cuál es la mejor manera de alimentar este tipo de información de la capa lógica de negocios a otra capa en una aplicación (como una vista), preferiblemente de una manera genérica que se pueda reutilizar para diferentes tipos de datos y operaciones?

¿Fue útil?

Solución

Si entiendo, tiene una situación en la que algunas solicitudes pueden pasar y otras pueden fallar. No estoy seguro de dónde desea que regrese el error, pero podría tener uno de los siguientes (o una variante, o una combinación):

  • Una lista de errores y los objetos de dominio afectados. Un objeto de dominio base o algo con una identificación persistible podría ser útil para la reutilización. Por ejemplo, una colección de errores que se refieren a objetos de dominio.
  • Puede inyectar (AOP, DI) en el objeto de la persona algún tipo de objeto/mensaje de error. Por ejemplo, if (persona. Errores) {...}
  • Puede envolver la recopilación de la persona en un mensaje con encabezado, cuerpo, información de error
  • Todos sus objetos de dominio podrían incluir una colección de errores accesible a través de una interfaz; o la persona apoya la interfaz ihaserrors. Puede hacer esto genérico y usar un objeto de error base que advierte y validación y todo tipo de cosas.

Si se encuentra en un sistema genuino de niveles múltiples (en lugar de en capas), puede tener una arquitectura basada en mensajes que podría acomodar fácilmente algún tipo de error genérico/advertencia/validación. Los sistemas SOA/AJAX se prestan a esto.

Feliz de profundizar un poco más si tiene algunas preguntas específicas.

Otros consejos

Esta pregunta destaca diferencias importantes entre los usos apropiados del manejo de excepciones, las transacciones y la idea flujo de trabajo "compensación" A qué es lo que el solicitante está tratando de afirmar, cuando declara correctamente:

Esto parece un tipo de problema que ocurriría en muchas aplicaciones y debería haber una forma limpia de manejarlo.

Es un problema común, primero algunos antecedentes sobre el enfoque transaccional que está intentando actualmente:

Las transacciones de datos se modelaron originalmente después de la contabilidad de doble entrada: una sola crédito y un correspondiente débito tuvieron que ser grabados juntos o no en absoluto. A medida que las transacciones se vuelven más grandes que esto, se vuelven cada vez más problemáticas de implementar correctamente y más difíciles de lidiar con una falla. A medida que comienza a llevar la idea de una sola transacción a través de los límites del sistema, lo más probable es que se acerque mal. Se puede hacer, pero requiere coordinadores de transacciones complejos y necesariamente de mayor latencia. A cierta escala, las transacciones son la mentalidad incorrecta, y la compensación comienza a tener mucho más sentido.

Aquí es donde regresas y miras lo que realmente hace el negocio. Es muy probable que una sola transacción no sea la forma en que la gente de negocios la ve. Por lo general, ven un paso completado, y dependiendo de los resultados posteriores, pueden ser necesarias diferentes acciones para compensar. Aquí es la idea de un flujo de trabajo y compensación viene en. Aquí hay una introducción a esos conceptos

Por ejemplo, si solicita un libro de Amazon, probablemente no "bloqueen" el registro mientras está en su carrito de compras, o incluso usa transacciones estrictas para determinar si el libro todavía está en stock cuando se confirma el pedido. De todos modos, se lo venderán y lo enviarán cuando puedan. Si no han logrado ponerlo en stock en unas pocas semanas, probablemente le enviarán un correo electrónico diciéndole que están tratando de satisfacer sus necesidades, y puede seguir esperando que lo pongan en cuenta o usted. puede cancelar su pedido. Esto se llama compensación y es necesario en muchos procesos comerciales del mundo real.

Finalmente, hay nada excepcional sobre todo esto. Espere que esto pueda suceder y use el flujo de control normal. No debe usar las funciones de manejo de excepciones de su idioma aquí (Buenas reglas para cuándo lanzar una excepción). Tampoco debe confiar en los mecanismos específicos de la herramienta (¿WCF?) Para ver o manejar excepciones que ocurren dentro de la implementación del servicio. La comunicación de fallas debe ser una parte normal de su contrato de datos (contratos de fallas).

Desafortunadamente, por "forma limpia de manejarlo", no hay una bandera para establecer que se cuide mágicamente, debe continuar descomponiendo el problema y lidiar con todas las piezas resultantes. Esperemos que estos conceptos lo conecten con lo que otras personas han hecho al tratar con este problema.

Resumen:

  • Su problema ha superado el concepto de una transacción -> Busque la compensación del flujo de trabajo.

Buena suerte -

Preferiría devolver una colección de objetos de error hechos a medida que identifican el objeto, que se efectúa por el error, el código de error y la descripción. De esta manera, los errores se pueden intentar remediar o mostrar más al usuario.

¡Creo que realmente estás en exceso de excepciones si estás pensando en estos términos!

Está perfectamente bien devolver los valores que significan falla, en lugar de lanzar una excepción. A menudo es mejor. Las excepciones se usan mejor cuando no puede recuperarse al nivel de abstracción en el que se encuentra, pero no debe usarlas como el principal medio de control del flujo de control o sus programas serán muy difíciles de leer.

El servicio web no devuelve excepciones, devuelve códigos y mensajes de devolución. Almacenaría una representación útil que presenta la información devuelta y devuelve la lista de aquellos para la vista o lo que sea que la vea.

Idealmente, la llamada a su servicio web debería ser así.

List<Person> selectedPeople = ... //fetch list of people
callLotteryNumberWebService(selectedPeople.ToArray );

Hacer una llamada de servicio web para cada persona es costoso. Al final del servidor, debe iterar sobre la lista y realizar la operación. El código del lado del servidor puede lanzar 2 excepciones: BulkoperationFailedException: si hay un error fatal debido a que falta el archivo DB o la configuración. Procesamiento adicional no es posible. BulkoperationException: esto contiene una variedad de excepciones relacionadas con una persona. Puede persistir alguna identificación para referirse de manera única a cada objeto. Su código será así:

List<Person> selectedPeople = ... // fetch list of people 

try{
    callLotteryNumberWebService(selectedPeople.ToArray);
}catch  (BulkOperationFailedException e) {
    SOP("Some config file missing/db down.No person records processed")
}catch(BulkOperationException e)  {
    UserDefinedExceptions us =  e.getExceptions()
    foreach(exception ein us)   {
        // read unique id to find which person object failed
    }
}

construct msg based on which personobject succeeded and which failed

La operación se considera exitosa cuando no se lanzan excepciones. Puede tener códigos de error personalizados para fallas en lugar de usar excepciones definidas por el usuario. Construir la BulkoperationException en el lado del servidor es complicado. En segundo lugar, debe clasificar los errores lanzados desde el lado del servidor en BulkoperationFailedException y BulkoperationException. Así era como había manejado en uno de mis proyectos.

Buscaría DTOS para este tipo de tarea. El DTO también podría incluir información sobre si lo persistente era exitoso o no y otros tipos de "metadatos".

Probablemente devolvería un mapa de resultados de tipo Map<Person,Future<String>> de mi getLotteryNumbers<Collection<Person>> Servicio.

Luego iteraría a través del mapa y usaría el Future.get() Para obtener el número de lotería o la excepción lanzada.

En algunos de mis servicios, me gusta implementar todas las llamadas como llamadas de elementos individuales y luego tener una lógica en mi servicio para lanzarlas y procesarlas como grupo. El lote se implementa utilizando un LinkedBlockingQueue y un hilo de votación.

En este escenario devuelvo un Future<Thing> lo que espera que los resultados del lote estén disponibles utilizando un CountdownLatch.

Eche un vistazo a la concurrencia de Java en la práctica para ver cómo estos componentes pueden funcionar juntos http://jcip.net/

Otra forma, especialmente para los sistemas de alto rendimiento, sería utilizar un diseño basado en colas donde una entidad de procesamiento realizaría operaciones en un objeto y luego en base a los resultados colocar el objeto en diferentes colas para el procesamiento adicional por otras entidades y luego seguir adelante. . Esto reduciría los cuellos de botella que surgirían debido al procesamiento adicional que se requeriría, por ejemplo, el procesamiento del pedido de los productos agotados

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top