@Override public void save(SagaInstance sagaInstance) { sagaInstance.setId(idGenerator.genId().asString()); logger.info("Saving {} {}", sagaInstance.getSagaType(), sagaInstance.getId()); jdbcTemplate.update(insertIntoSagaInstanceSql, sagaInstance.getSagaType(), sagaInstance.getId(), sagaInstance.getStateName(), sagaInstance.getLastRequestId(), sagaInstance.getSerializedSagaData().getSagaDataType(), sagaInstance.getSerializedSagaData().getSagaDataJSON()); saveDestinationsAndResources(sagaInstance); }
private void saveDestinationsAndResources(SagaInstance sagaInstance) { for (DestinationAndResource dr : sagaInstance.getDestinationsAndResources()) { try { jdbcTemplate.update(insertIntoSagaInstanceParticipantsSql, sagaInstance.getSagaType(), sagaInstance.getId(), dr.getDestination(), dr.getResource() ); } catch (DuplicateKeyException e) { // do nothing } } }
@Override public void update(SagaInstance sagaInstance) { logger.info("Updating {} {}", sagaInstance.getSagaType(), sagaInstance.getId()); int count = jdbcTemplate.update(updateSagaInstanceSql, sagaInstance.getStateName(), sagaInstance.getLastRequestId(), sagaInstance.getSerializedSagaData().getSagaDataType(), sagaInstance.getSerializedSagaData().getSagaDataJSON(), sagaInstance.getSagaType(), sagaInstance.getId()); Assert.isTrue(count == 1, "Should be 1 : " + count); saveDestinationsAndResources(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().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; }
sagaInstance.addDestinationsAndResources(singleton(new DestinationAndResource(destination, lockedTarget))); }); String currentState = sagaInstance.getStateName(); maybePerformEndStateActions(sagaId, sagaInstance, possibleNewState); updateEnlistedAggregates(sagaId, actions.getEnlistedAggregates()); sagaInstance.setLastRequestId(sendCommands(sagaId, commands)); updateEventInstanceSubscriptions(sagaData, sagaId, sagaInstance.getStateName()); sagaInstance.setSerializedSagaData(SagaDataSerde.serializeSagaData(sagaData));
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().start(sagaData); processActions(sagaId, sagaInstance, sagaData, actions); return sagaInstance; }
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 find(String sagaType, String sagaId) { logger.info("finding {} {}", sagaType, sagaId); Set<DestinationAndResource> destinationsAndResources = new HashSet<>(jdbcTemplate.query( selectFromSagaInstanceParticipantsSql, (rs, rownum) -> new DestinationAndResource(rs.getString("destination"), rs.getString("resource")), sagaType, sagaId)); return DataAccessUtils.requiredSingleResult(jdbcTemplate.query( selectFromSagaInstanceSql, (rs, rownum) -> new SagaInstance(sagaType, sagaId, rs.getString("state_name"), rs.getString("last_request_id"), new SerializedSagaData(rs.getString("saga_data_type"), rs.getString("saga_data_json")), destinationsAndResources), sagaType, sagaId)); // TODO insert - sagaInstance.getDestinationsAndResources(); }
@Override public void save(SagaInstance sagaInstance) { sagaInstance.setId(SAGA_ID); this.sagaInstance = 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); }
@Override public <Data> SagaInstanceData<Data> findWithData(String sagaType, String sagaId) { SagaInstance sagaInstance = find(sagaType, sagaId); Data sagaData = SagaDataSerde.deserializeSagaData(sagaInstance.getSerializedSagaData()); return new SagaInstanceData<>(sagaInstance, sagaData); }
private void performEndStateActions(String sagaId, SagaInstance sagaInstance) { for (DestinationAndResource dr : sagaInstance.getDestinationsAndResources()) { Map<String, String> headers = new HashMap<>(); headers.put(SagaCommandHeaders.SAGA_ID, sagaId); headers.put(SagaCommandHeaders.SAGA_TYPE, getSagaType()); // FTGO SagaCommandHandler failed without this but the OrdersAndCustomersIntegrationTest was fine?!? commandProducer.send(dr.getDestination(), dr.getResource(), new SagaUnlockCommand(), makeSagaReplyChannel(), headers); } }
@Override public SagaInstance find(String sagaType, String sagaId) { logger.info("finding {} {}", sagaType, sagaId); Set<DestinationAndResource> destinationsAndResources = new HashSet<>(jdbcTemplate.query( selectFromSagaInstanceParticipantsSql, (rs, rownum) -> new DestinationAndResource(rs.getString("destination"), rs.getString("resource")), sagaType, sagaId)); return DataAccessUtils.requiredSingleResult(jdbcTemplate.query( selectFromSagaInstanceSql, (rs, rownum) -> new SagaInstance(sagaType, sagaId, rs.getString("state_name"), rs.getString("last_request_id"), new SerializedSagaData(rs.getString("saga_data_type"), rs.getString("saga_data_json")), destinationsAndResources), sagaType, sagaId)); // TODO insert - sagaInstance.getDestinationsAndResources(); }
private Object assignSagaIdWhenSaved(InvocationOnMock invocation) { SagaInstance sagaInstance = invocation.getArgument(0); sagaInstance.setId(sagaId); return null; }
private void performEndStateActions(String sagaId, SagaInstance sagaInstance, boolean compensating, Data sagaData) { for (DestinationAndResource dr : sagaInstance.getDestinationsAndResources()) { Map<String, String> headers = new HashMap<>(); headers.put(SagaCommandHeaders.SAGA_ID, sagaId); headers.put(SagaCommandHeaders.SAGA_TYPE, getSagaType()); // FTGO SagaCommandHandler failed without this but the OrdersAndCustomersIntegrationTest was fine?!? commandProducer.send(dr.getDestination(), dr.getResource(), new SagaUnlockCommand(), makeSagaReplyChannel(), headers); } if (compensating) saga.onSagaRolledBack(sagaId, sagaData); else saga.onSagaCompletedSuccessfully(sagaId, sagaData); }
@Override public void update(SagaInstance sagaInstance) { logger.info("Updating {} {}", sagaInstance.getSagaType(), sagaInstance.getId()); int count = jdbcTemplate.update(updateSagaInstanceSql, sagaInstance.getStateName(), sagaInstance.getLastRequestId(), sagaInstance.getSerializedSagaData().getSagaDataType(), sagaInstance.getSerializedSagaData().getSagaDataJSON(), sagaInstance.getSagaType(), sagaInstance.getId()); Assert.isTrue(count == 1, "Should be 1 : " + count); saveDestinationsAndResources(sagaInstance); }
private void saveDestinationsAndResources(SagaInstance sagaInstance) { for (DestinationAndResource dr : sagaInstance.getDestinationsAndResources()) { try { jdbcTemplate.update(insertIntoSagaInstanceParticipantsSql, sagaInstance.getSagaType(), sagaInstance.getId(), dr.getDestination(), dr.getResource() ); } catch (DuplicateKeyException e) { // do nothing } } }
private SagaInstance makeExpectedSagaInstanceAfterSecondStep() { return new SagaInstance(sagaType, sagaId, "state-B", requestId2.asString(), SagaDataSerde.serializeSagaData(sagaDataUpdatedByReplyHandler), Collections.emptySet()); }
private SagaInstance makeExpectedSagaInstanceAfterFirstStep() { return new SagaInstance(sagaType, sagaId, "state-A", requestId1.asString(), SagaDataSerde.serializeSagaData(sagaDataUpdatedByStartingHandler), Collections.emptySet()); }