private void startSaga() { when(sagaDefinition.start(initialSagaData)).thenReturn(makeFirstSagaActions()); when(sagaCommandProducer.sendCommands(anyString(), anyString(), anyList(), anyString())) .thenReturn(requestId1.asString()); doAnswer(this::assignSagaIdWhenSaved).when(sagaInstanceRepository).save(any(SagaInstance.class)); sagaInstance = sm.create(initialSagaData); SagaInstance expectedSagaInstanceAfterFirstStep = makeExpectedSagaInstanceAfterFirstStep(); assertSagaInstanceEquals(expectedSagaInstanceAfterFirstStep, sagaInstance); verify(sagaCommandProducer).sendCommands(sagaType, sagaId, Collections.singletonList(commandForParticipant1), sagaReplyChannel); verify(sagaInstanceRepository).save(any(SagaInstance.class)); verify(sagaInstanceRepository).update(argThat(sagaInstance -> sagaInstanceEquals(expectedSagaInstanceAfterFirstStep, sagaInstance))); assertSagaInstanceEquals(expectedSagaInstanceAfterFirstStep, sagaInstance); verifyNoMoreInteractions(sagaInstanceRepository, sagaCommandProducer); }
private void handleReply(boolean compensating) { SagaInstance expectedSagaInstanceAfterSecondStep = makeExpectedSagaInstanceAfterSecondStep(); when(sagaInstanceRepository.find(sagaType, sagaId)) .thenReturn(sagaInstance); when(sagaDefinition.handleReply(anyString(), any(TestSagaData.class), any(Message.class))) .thenReturn(makeSecondSagaActions(compensating)); when(sagaCommandProducer.sendCommands(anyString(), anyString(), anyList(), anyString())).thenReturn (requestId2.asString()); sagaMessageHandler.accept(replyFromParticipant1); verify(sagaInstanceRepository).find(sagaType, sagaId); verify(sagaCommandProducer).sendCommands(sagaType, sagaId, Collections.singletonList(commandForParticipant2), sagaReplyChannel); verify(sagaInstanceRepository).update(argThat(sagaInstance -> sagaInstanceEquals(expectedSagaInstanceAfterSecondStep, sagaInstance))); assertSagaInstanceEquals(expectedSagaInstanceAfterSecondStep, sagaInstance); verifyNoMoreInteractions(sagaInstanceRepository, sagaCommandProducer); }
private void handleAggregateInstanceEvent(String sagaType, String sagaId, Message message, String aggregateType, String aggregateId, String eventType) { System.out.println("Got handleAggregateInstanceEvent: " + message + ", type=" + sagaType + ", instance=" + sagaId); SagaInstanceData<Data> sagaInstanceAndData = sagaInstanceRepository.findWithData(sagaType, sagaId); SagaInstance sagaInstance = sagaInstanceAndData.getSagaInstance(); Data sagaData = sagaInstanceAndData.getSagaData(); String currentState = sagaInstance.getStateName(); logger.info("Current state={}", currentState); Optional<SagaEventHandler<Data>> eventHandler = getStateDefinition().findEventHandler(saga, currentState, sagaData, aggregateType, Long.parseLong(aggregateId), eventType); if (!eventHandler.isPresent()) { logger.error("No event handler for: {}", message); return; } logger.info("Invoking event handler for {}", message); SagaActions<Data> actions = eventHandler.get().getAction().apply(sagaData, new DomainEventEnvelopeImpl<>(null, null, null, null, null)); // TOOD // TODO - doesn't this do something??? Commands sagaInstance.setSerializedSagaData(SagaDataSerde.serializeSagaData(sagaData)); sagaInstanceRepository.update(sagaInstance); }
@Override public SagaInstance create(Data sagaData, Optional<String> resource) { SagaInstance sagaInstance = new SagaInstance(getSagaType(), null, "????", null, SagaDataSerde.serializeSagaData(sagaData), new HashSet<>()); sagaInstanceRepository.save(sagaInstance); String sagaId = sagaInstance.getId(); resource.ifPresent( r -> Assert.isTrue(sagaLockManager.claimLock(getSagaType(), sagaId, r), "Cannot claim lock for resource")); SagaActions<Data> actions = getStateDefinition().start(sagaData); processActions(sagaId, sagaInstance, sagaData, actions); return sagaInstance; }
private void processActions(String sagaId, SagaInstance sagaInstance, Data sagaData, SagaActions<Data> actions) { String lastRequestId = sagaCommandProducer.sendCommands(this.getSagaType(), sagaId, actions.getCommands(), this.makeSagaReplyChannel()); sagaInstance.setLastRequestId(lastRequestId); actions.getUpdatedState().ifPresent(sagaInstance::setStateName); sagaInstance.setSerializedSagaData(SagaDataSerde.serializeSagaData(actions.getUpdatedSagaData().orElse(sagaData))); if (actions.isEndState()) { performEndStateActions(sagaId, sagaInstance, actions.isCompensating(), sagaData); } sagaInstanceRepository.update(sagaInstance); }
private void handleReply(Message message) { if (!isReplyForThisSagaType(message)) return; logger.debug("Handle reply: {}", message); String sagaId = message.getRequiredHeader(SagaReplyHeaders.REPLY_SAGA_ID); String sagaType = message.getRequiredHeader(SagaReplyHeaders.REPLY_SAGA_TYPE); SagaInstance sagaInstance = sagaInstanceRepository.find(sagaType, sagaId); Data sagaData = SagaDataSerde.deserializeSagaData(sagaInstance.getSerializedSagaData()); message.getHeader(SagaReplyHeaders.REPLY_LOCKED).ifPresent(lockedTarget -> { String destination = message.getRequiredHeader(CommandMessageHeaders.inReply(CommandMessageHeaders.DESTINATION)); sagaInstance.addDestinationsAndResources(singleton(new DestinationAndResource(destination, lockedTarget))); }); String currentState = sagaInstance.getStateName(); logger.info("Current state={}", currentState); SagaActions<Data> actions = getStateDefinition().handleReply(currentState, sagaData, message); logger.info("Handled reply. Sending commands {}", actions.getCommands()); processActions(sagaId, sagaInstance, sagaData, actions); }
@Override public SagaInstance create(Data sagaData, Optional<String> resource) { SagaInstance sagaInstance = new SagaInstance(getSagaType(), null, "????", null, SagaDataSerde.serializeSagaData(sagaData), new HashSet<>()); sagaInstanceRepository.save(sagaInstance); String sagaId = sagaInstance.getId(); resource.ifPresent( r -> Assert.isTrue(sagaLockManager.claimLock(getSagaType(), sagaId, r), "Cannot claim lock for resource")); SagaActions<Data> actions = getStateDefinition().getStartingHandler().get().apply(sagaData); List<CommandWithDestination> commands = actions.getCommands(); sagaData = actions.getUpdatedSagaData().orElse(sagaData); sagaInstance.setLastRequestId(sendCommands(sagaId, commands)); sagaInstance.setSerializedSagaData(SagaDataSerde.serializeSagaData(sagaData)); publishEvents(sagaId, actions.getEventsToPublish(), actions.getUpdatedState()); Optional<String> possibleNewState = actions.getUpdatedState(); maybeUpdateState(sagaInstance, possibleNewState); maybePerformEndStateActions(sagaId, sagaInstance, possibleNewState); sagaInstanceRepository.update(sagaInstance); updateEnlistedAggregates(sagaId, actions.getEnlistedAggregates()); updateEventInstanceSubscriptions(sagaData, sagaId, sagaInstance.getStateName()); return sagaInstance; }
String messageJson = message.getPayload(); SagaInstanceData<Data> sagaInstanceAndData = sagaInstanceRepository.findWithData(sagaType, sagaId); SagaInstance sagaInstance = sagaInstanceAndData.getSagaInstance(); Data sagaData = sagaInstanceAndData.getSagaData(); sagaInstanceRepository.update(sagaInstance);