当前位置: 首页 > 知识库问答 >
问题:

精心策划的传奇故事无法“存活”服务失败

云骏奇
2023-03-14

假设您有两个不同的微服务(Customer和Account),它们都作为Spring Boot应用程序在Docker容器中运行。每次创建新客户时,也应创建相应的帐户。为了编排这个流程,我有第三个“服务”来实现基于编排的传奇逻辑。

传奇“服务”包含以下代码。

@Saga
public class CustomerAccountSaga {

    private static final String ACCOUNT_CREATION_DEADLINE = "sagas.account-creation-deadline";

    private static final Logger LOGGER = LogManager.getLogger(CustomerAccountSaga.class);


    @Autowired
    private transient CommandGateway commandGateway;

    @Autowired
    private transient DeadlineManager deadlineManager;


    private String customerId;

    private String accountDeadlineId;



    @StartSaga
    @SagaEventHandler(associationProperty = "aggregateId")
    private void on(CustomerCreatedEvent event) {
        if(LOGGER.isDebugEnabled()) {
        LOGGER.debug("A new customer has been created for id = '{}'", event.getAggregateId());
        }
    
        this.customerId = event.getAggregateId().getId();
        SagaLifecycle.associateWith("customerId", customerId);
    
        //Both services has a CustomerId class defined in another package.
        b.t.c.a.v.CustomerId id = new b.t.c.a.v.CustomerId(customerId);
        CreateAccountCommand createAccount = new CreateAccountCommand(id);
        commandGateway.send(createAccount);
    
        this.accountDeadlineId = deadlineManager.schedule(Duration.ofDays(1), ACCOUNT_CREATION_DEADLINE);
    }

    @SagaEventHandler(associationProperty = "aggregateId")
    private void on(CustomerDeletedEvent event) {
        if(LOGGER.isDebugEnabled()) {
            LOGGER.debug("A customer with id '{}' has been deleted. "
                    + "The customer was deleted before the account was created, "
                    + "or the request to create the account timed-out", 
                    event.getAggregateId());
        }
        deadlineManager.cancelSchedule(ACCOUNT_CREATION_DEADLINE, accountDeadlineId);
        SagaLifecycle.end();
    }

    @SagaEventHandler(associationProperty = "customerId")
    private void on(AccountCreatedEvent event) {
        if(LOGGER.isDebugEnabled()) {
            LOGGER.debug("A corresponding account for customer with id '{}' has been created", 
                    event.getCustomerId());
        }
        deadlineManager.cancelSchedule(ACCOUNT_CREATION_DEADLINE, accountDeadlineId);
        SagaLifecycle.end();
    }

    @DeadlineHandler(deadlineName = ACCOUNT_CREATION_DEADLINE)    
    public void on() {
        if(LOGGER.isDebugEnabled()) {
            LOGGER.debug("Failed to create a new account for customer with id '{}' in a timely fashion", 
                    customerId);
        }
    
        //Both services has a CustomerId class defined in another package.
        b.t.c.c.v.CustomerId id = new b.t.c.c.v.CustomerId(customerId);
        DeleteCustomerCommand deleteCustomer = new DeleteCustomerCommand(id);
        commandGateway.send(deleteCustomer);
    }

}

当所有服务都启动并运行时,一切正常。CustomerCreatedEvent由saga处理程序处理,并按预期激发CreateCountCommand。后者导致创建帐户并触发AccountCreatedEvent,这也由saga逻辑处理。

当我尝试以下场景时,问题就出现了。在所有情况下,客户服务都在运行。

场景A

  1. 使用客户服务创建新客户

方案B

  1. 使用客户服务创建新客户

方案C

客户和帐户服务都已启动并运行。saga服务离线。

  1. 创建一个新客户。
  2. 启动saga服务。我再次期望saga服务拾取CustomerCreatedEvent并继续,但它没有。

由于在所有情况下都不会发生预期行为,因此应用程序将处于不一致状态,因为不允许存在没有相应帐户的客户。

saga服务使用以下配置为Quartz和Axon为MySQL配置了一个持久存储。Axon对事件使用Jackson序列化器。

# Persistence configuration (MySQL) 
###################################
# Quartz persistence
spring.quartz.job-store-type=jdbc
spring.quartz.jdbc.initialize-schema=always
spring.quartz.properties.org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
spring.quartz.properties.org.quartz.jobStore.dataSource=dsQuartz
spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_
spring.quartz.properties.org.quartz.dataSource.dsQuartz.user = ******
spring.quartz.properties.org.quartz.dataSource.dsQuartz.password = *******
spring.quartz.properties.org.quartz.dataSource.dsQuartz.maxConnections = 10
spring.quartz.properties.org.quartz.dataSource.dsQuartz.driver = com.mysql.cj.jdbc.Driver
spring.quartz.properties.org.quartz.dataSource.dsQuartz.URL = jdbc:mysql://192.168.99.100:3306/saga-store

# Axon persistence
spring.datasource.url=jdbc:mysql://192.168.99.100:3306/saga-store
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.username=******
spring.datasource.password=*****
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=update

问题:我是否误解了微服务和编配传奇的一些基本概念,或者我在设置/设计包含业务逻辑和编配传奇逻辑的不同微服务时忽略了什么?

谢谢你阅读我的帖子,并指出我错在哪里。

共有1个答案

贡俊
2023-03-14

在不了解您的设置的情况下,我会说这一切都取决于配置。所以,基本上,当你启动一个@Saga时,它在引擎盖下还有一个流式事件处理器,它可以从尾部(最旧的事件)或头部(最新的事件)开始。

如ref指南所述,对于Saga流媒体处理器,默认为头。如果什么都没有配置,你的传奇故事只会对新的事件而不是过去的事件做出反应——你应该非常小心,在从一个事件切换到另一个事件之前好好考虑一下。

另一个需要注意的要点是关于Saga Store,如果没有配置任何内容,它会使用InMemorySagaStore。当然,这可能不理想,您会配置一个持久的。我们的参考指南再次提供了所有的部分。

 类似资料:
  • 服务调用失败 KernalEvent::SERVICE_FAIL事件 在框架层,调用servcie时,会抛出KernalEvent::SERVICE_FAIL事件,你可以监听该事件,做数据上报处理,请以异步方式上报 配置config/lister.php中的事件监听器 示例 <?php namespace src\Web\Listeners; class ServiceFailListener e

  • 我们不断收到此错误: 我们已经验证了activemq作为activemq运行,我们已经验证了目录的所有者是activemq。它不会自动创建目录,如果我们自己创建,它仍然会给出同样的错误。服务开始很好,但是它会不断地抛出同样的错误。没有锁定文件,因为它不会生成任何文件或目录。

  • 有人知道为什么。

  • 问题内容: 我正在创建应用程序并在其中使用一些hibernate的东西。我要做的就是将实体保存到数据库中,但我不断收到此异常: 起初,我遇到了这个异常: 然后,我发现需要将其添加到我的hibernate配置中: 这解决了这个问题,但是现在出现了上面的问题。我将实体保存到这样的数据库中: 我的hibernate.cfg.xml文件如下所示: 我在用: Hibernate-4.1.4.Final JD

  • 末流985,投了好多家游策都没啥反应,只有剑心和西山居无论实习还是春招都是给面子次次进(爱您,虽然前两次全部折戟,这一次还是笔试挂了被捞,大概是因为没实习+项目经验,但是有mmo经验保底) 作品集:MMO关卡拆解、MMO拆解、世界观设定、人物小传、UE4Demo、系统反策划案 目前拿了家小厂offer,就业困难没人要!在面剑心,想回馈一下牛客,所以就记下来啦! 2022.10.19 西山居 实习面

  • 当我录制这个命令以显示mongodb的状态时