DSL 7 - Manejo Timeouts
Si en algún momento desea ver la solución a este paso, puede encontrarla en el |
Action Timeouts
En esta sección, analizaremos cómo manejamos la acción basada en timeouts. Suponga que tenemos un flujo simple que realiza una llamada a un dominio externo, la llamada se realiza con éxito, pero luego nunca recibimos la respuesta asignada. En ese escenario, puede que deseemos realizar alguna forma de acción compensatoria.
Para ilustrar esto, vamos a utilizar nuestro sistema de Fraude y a examinar cómo hacemos frente a la falta de respuesta del dominio descendente.
Configuración de un Tiempo de Espera de Acción (en el DSL)
Configurando action timeouts en el DSL es simple, todo lo que necesitamos hacer es agregar un tipo especial de Event Línea de comportamiento para indicar al flujo qué enfoque compensatorio adoptar.
Comencemos, por lo tanto, abriendo MPS y yendo a nuestro flujo. Entonces, añadamos un nuevo Event Comportamiento ("Agregar Event Comportamiento").
Agreguemos los fundamentos de nuestro event comportamiento al decir que está en la "Verificación de Fraude" state-eso es el state estaríamos en caso de haber realizado con éxito nuestra llamada al sistema de fraude.
Ahora desde el "Para Event ", elegimos un nuevo tipo que no hemos utilizado antes" - el "Tiempo de Espera de Acción"
Una vez seleccionado, debemos elegir la acción que corresponde:
Lo primero que debe señalar aquí es el valor predeterminado que se ha aplicado "Cualquier acción" - esto significa que un tiempo de espera de "cualquier acción" en la "verificación de fraude" state invocará el comportamiento. En nuestro caso, solo invocamos la acción "Verificar Fraude" al comprobar el fraude, por lo que no hace demasiada diferencia, pero puede haber ocasiones en las que estemos activando múltiples acciones y deseemos manejar el resultado de cualquiera de ellas que se agote.
Para nuestro escenario, puede dejar el valor predeterminado como "Cualquier acción" (ya que solo hay una acción) o simplemente seleccionar "Verificar Fraude" (ambas opciones funcionarán aquí).
Ahora necesitamos ingresar el "Mover a State " y "Realizar Acciones" según cualquier otro event comportamiento. Aquí podríamos hacer cualquier cosa que normalmente nos gustaría llamar otras acciones,decisions etc. Sin embargo, para simplificar en este tutorial, simplemente moveremos nuestro flujo a un "Tiempo de espera" state.
Así que añadamos un nuevo state llamado "Tiempo de espera", lo marcaremos como terminal para tratarlo como el final del flujo y para informar a nuestro flujo de iniciación sobre lo que está sucediendo.
y establezca eso para nuestro movimiento a state. No realizaremos más acciones.
Nuestro event el comportamiento se verá como:
Eso es todo nuestro trabajo de DSL, ahora revisemos nuestro gráfico para nuestro flujo.
Abra el flujo yendo a . Esto abrirá el flujo y a primera vista, esto no parece diferente. Sin embargo, en la parte superior del panel veremos:
Así que ahora tenemos una nueva opción "Mostrar Timeouts ". Haga clic en esa casilla y "Aplique" las actualizaciones (nota-si ya tiene Flo Viewer abierto, puede que deba cerrarlo y volver a abrirlo para ver "Mostrar Timeouts ").
El nuevo gráfico mostrará:
Aquí podemos ver que, en el tiempo de espera de la verificación de fraude, estamos redirigiendo a la nueva opción de Tiempo Agotado.state.
Tenga en cuenta también que el gráfico muestra que esta transición ocurrirá en el "CheckFraudActionTimeoutEvent".event. Esto event se genera por la aplicación cuando la llamada de fraude se agota.
Java Implementación
Como es habitual, comencemos nuestra implementación regenerando nuestra base de código.
mvn clean install
Comencemos por observar un poco cómo funciona el código.
Comenzará abriendo la interfaz "SchedulerPort" (parte del IPF Core):
public interface SchedulerPort {
void schedule(ScheduleItem var1, Function<ScheduleItem, CompletableFuture<Void>> var2);
void schedule(ScheduleItem var1, Function<ScheduleItem, CompletableFuture<Void>> var2, Duration var3);
void cancel(ScheduleItem var1);
void cancelAll(String var1);
int getRetries(ScheduleItem var1);
}
Son estas funciones las que el código generado invocará cada vez que necesite establecer un horario. En nuestro caso, cada vez que se llame a una acción, invocará el método de programación y proporcionará un Elemento de Programación que contiene los detalles de la acción y un tipo de "TIMEOUT".
Así que si usted especifica a la scheduler que desea un tiempo de espera de 10s en esta acción, entonces devolverá un fallo después de 10s si el programa sigue activo. Sin embargo, si en ese tiempo se llama a una cancelación, entonces esto cerrará el scheduler.
El IPF application necesita una implementación del scheduler el puerto debe ser proporcionado como parte del dominio. Sin embargo, hasta ahora no hemos tenido que especificar uno. ¿Por qué es esto? Es porque, por defecto, una operación no realiza ninguna acción.scheduler se proporciona. Lo que necesitamos hacer ahora es proporcionar una implementación adecuada para nuestro caso.
El Akka Scheduler
Usted podría aquí utilizar cualquier scheduler que se ajusta a la definición de interfaz anterior, para este tutorial utilizaremos otro proporcionado por el IPF framework, el AkkaScheduler.
Comencemos añadiendo una dependencia en el pom de nuestra aplicación ipf-tutorial-app (ipf-tutorial-app/pom.xml):
<dependency>
<groupId>com.iconsolutions.ipf.core.platform</groupId>
<artifactId>ipf-flo-scheduler-akka</artifactId>
</dependency>
(nota-puede que necesite recargar Maven para descargar la dependencia)
Al agregar la dependencia, Spring inyectará automáticamente una instancia del scheduler en nuestra aplicación. Por lo tanto, todo lo que necesitamos hacer es configurar nuestro dominio para utilizarlo, para esto simplemente debemos actualizar la declaración del dominio en IpfTutorialConfig.java para especificar el scheduler adaptador:
@Bean
public IpftutorialmodelDomain init(ActorSystem actorSystem, SchedulerPort schedulerAdapter) { (1)
// All adapters should be added to the domain model
return new IpftutorialmodelDomain. Builder(actorSystem)
.withTutorialDomainFunctionLibraryAdapter(input -> CompletableFuture.completedStage(new DuplicateCheckResponseInput. Builder(input.getId(), AcceptOrRejectCodes. Accepted).build()))
.withAccountingSystemActionAdapter(new SampleAccountingSystemActionAdapter())
.withFraudSystemActionAdapter(new FraudSystemActionAdapter())
.withDecisionLibraryAdapter(input ->
input.getCustomerCreditTransfer().getCdtTrfTxInf().get(0).getIntrBkSttlmAmt().getValue().compareTo(BigDecimal. TEN)>0?
RunFraudCheckDecisionOutcomes. FRAUDREQUIRED: RunFraudCheckDecisionOutcomes. SKIPFRAUD)
.withIpftutorialflowAggregateFunctionAdapter(input -> new ExtractCreditorAccountForFlowIpftutorialflowAggregateFunctionOutput(input.getCustomerCreditTransfer().getCdtTrfTxInf().get(0).getCdtrAcct()))
.withSchedulerAdapter(schedulerAdapter) (2)
.build();
}
| 1 | Tenga en cuenta la adición de SchedulerPort a la firma de init |
| 2 | Agregando el Scheduler Adaptador al dominio |
Eso es todo desde la perspectiva del código.
Configuración
Nuestro trabajo final es configurar nuestro scheduler. La configuración se realiza utilizando propiedades, la cadena de propiedades que requerimos tiene el formato:
ipf flow.<FLOW_NAME>.<STATE_NAME>.<ACTION_NAME>.timeout-duration=<DURATION> |
Lo primero que debe tener en cuenta aquí es que necesitamos proporcionar los valores de los tres parámetros opcionales.- nuestro nombre de flujo,state nombre, nombre de la acción-y proporcione el valor para la duración.
En nuestro caso, entonces, nuestra propiedad debería verse así:
ipf flow. Ipftutorialflow. CheckingFraud. CheckFraud.timeout-duration=2s |
Lo primero que debe tener en cuenta al definir esta propiedad es que donde tengamos espacios en cualquiera de los componentes, simplemente ignoramos el espacio. Así que, por ejemplo, nuestro nombre de acción es en realidad Check Fraud pero simplemente utilizamos CheckFraud. También estamos especificando una duración aquí de 2 segundos.
Agreguemos esta propiedad a la configuración de la aplicación. Para hacer esto, abra el archivo docker/config/ipf-tutorial-app/application.conf y añada la línea anterior.
Habilitando una Configuración de Prueba
Estamos casi listos para probar nuestro tiempo de espera; lo único que queda es hacer que la llamada de verificación de fraude tenga la capacidad de expirar. Actualicemos la definición de la verificación de fraude que proporcionamos anteriormente para no utilizar el adaptador de fraude de muestra, sino para permitir también un tiempo de espera opcional. Creamos un nuevo paquete en nuestro proyecto ipf-tutorial-app para las implementaciones de adaptadores.-com.iconsolutions.ipf.tutorial.app.adapters.
Luego, en nuestro nuevo paquete, añadiremos una implementación de FraudActionPort.
Utilizará la idea de " magic values "para decir que si se recibe un pago de valor >= 50 USD por la llamada de fraude, se agotará el tiempo, de lo contrario, se devolverá con éxito. Intente implementar esta lógica usted mismo (Sugerencia" - Consulte el ejemplo de clase generado Sample Fraud System Action Adapter en domain-root/sampleapp como punto de partida). Cuando esté listo, compare su intento con la solución proporcionada a continuación:
@Slf4j
public class FraudSystemActionAdapter implements FraudSystemActionPort {
@Override
public CompletionStage<Void> execute(final CheckFraudAction action) {
log.debug("Received an action of type {} for id {}", action.getActionName(), action.getId());
if (action.getCustomerCreditTransfer().getCdtTrfTxInf().get(0).getIntrBkSttlmAmt().getValue().compareTo(new BigDecimal("50")) >= 0) {
return CompletableFuture.runAsync(() -> log.debug("Pretending to timeout the fraud call for aggregate {}", action.getProcessingContext().getAssociationId()));
} else {
return IpftutorialmodelDomain.fraudSystem().handle(new FraudCheckResponseInput. Builder(action.getId(), AcceptOrRejectCodes. Accepted).build())
.thenAccept(done -> log.debug("Sent input of type {} for id {} with result {}", done.getCommandName(), action.getId(), done.getResult().name()));
}
}
}
|
Finalmente, necesitamos agregar nuestro nuevo adaptador a nuestra configuración como de costumbre (estamos cambiando el.with Fraud System Action Adapter para utilizar nuestro adaptador recién creado).FraudSystemActionAdapter):
@Bean
public IpftutorialmodelDomain init(ActorSystem actorSystem, SchedulerPort schedulerAdapter) {
// All adapters should be added to the domain model
return new IpftutorialmodelDomain. Builder(actorSystem)
.withDomainFunctionAdapter(input -> CompletableFuture.completedStage(new DuplicateCheckResponseInput. Builder(input.getId(), AcceptOrRejectCodes. Accepted).build()))
.withAccountingSystemActionAdapter(new SampleAccountingSystemActionAdapter())
.withFraudSystemActionAdapter(new FraudSystemActionAdapter())
.withDecisionAdapter(input ->
input.getCustomerCreditTransfer().getCdtTrfTxInf().get(0).getIntrBkSttlmAmt().getValue().compareTo(BigDecimal. TEN)>0?
RunFraudCheckDecisionOutcomes. FRAUDREQUIRED: RunFraudCheckDecisionOutcomes. SKIPFRAUD)
.withIpftutorialflowAggregateFunctionAdapter(input -> new ExtractCreditorAccountForFlowIpftutorialflowAggregateFunctionOutput(input.getCustomerCreditTransfer().getCdtTrfTxInf().get(0).getCdtrAcct()))
.withSchedulerAdapter(schedulerAdapter)
.build();
}
Eso es todo completo, es hora de construir y activar el entorno del contenedor para verificar que todo funcione:
Verificando nuestra Solución
Como es habitual, ahora verifique que la solución funcione. Inicie la aplicación como se indicó anteriormente (instructions están disponibles en Revisando la solicitud inicial si necesita un repaso)
Para los pagos, necesitamos reconsiderar la lógica que hemos construido:
-
Si un pago es superior a $50 (pero superior a 10 para asegurarse de que se requiere la verificación de fraude), entonces se agota el tiempo; si no, procedemos como antes.
Así que intentemos ambos escenarios comenzando con un pago superior a $50:
curl -X POST localhost:8080/submit -H 'Content-Type: application/json' -d '{"value": "150"}' | jq
Hablemos del pago en el Developer GUI y mencione el domain events ver (buscar por unit of work id, haga clic en ver, haga clic domain events):
Aquí podemos ver que esta vez hemos logrado con éxito el tiempo de espera.event viniendo. Para confirmación, si ahora repetimos el proceso con un valor de, digamos, $25, veremos que la verificación de fraude se ha procesado con éxito y no ha expirado, por lo que nuestro flujo ha continuado hasta su finalización.
Persistent Scheduling
IPF proporciona otro scheduling interfaz por defecto. Esta es la persistent scheduler. Es quartz respaldado y la principal diferencia es que está respaldado por una capa de persistencia y, como tal, si la aplicación falla, los horarios estarán disponibles después jvm apagado.
Para aplicar el persistent scheduler simplemente necesitamos reemplazar el akka scheduler dependencia con la de nuestro persistent scheduler:
<dependency>
<groupId>com.iconsolutions.ipf.core.platform</groupId>
<artifactId>ipf-flo-scheduler-persistent</artifactId>
</dependency>
Si lo desea, adelante y pruebe este cambio, puede repetir las pruebas que realizamos anteriormente para demostrar que nuestro nuevo scheduler está funcionando.