Axon org.axonframework.commandhandling.nohandlerforcommandexception: известно, что узел не принимает

При попытке реализовать DistributedCommandBus с помощью Spring Cloud я периодически получаю следующую ошибку. У меня есть основания полагать, что существует какое-то состояние гонки, происходящее с автоконфигурацией моего совокупного корневого класса, его обработчиков команд и моего класса bean-компонента конфигурации.

org.axonframework.commandhandling.NoHandlerForCommandException: No node known to accept.

Я использую Axon Version 3.3.5.

Вот мой класс конфигураций:

@Configuration
@AutoConfigureBefore(CustomerAggregate.class)
public class AxonConfig {
    @Value("${mongo.servers}")
    private String mongoUrl;

    @Value("${mongo.db}")
    private String mongoDbName;

    @Value("${axon.events.collection.name}")
    private String eventsCollectionName;

    @Value("${axon.snapshot.collection.name}")
    private String snapshotCollectionName;

    @Value("${axon.saga.collection.name}")
    private String sagaCollectionName;

    @Bean
    @Primary
    public CommandGateway commandGateway(@Qualifier("distributedBus") DistributedCommandBus commandBus) throws Exception {
        return new DefaultCommandGateway(commandBus, new IntervalRetryScheduler(Executors.newSingleThreadScheduledExecutor(), 1000, 10));
    }

    @Bean
    @Primary
    @Qualifier("springCloudRouter")
    public CommandRouter springCloudCommandRouter(DiscoveryClient client, Registration localServiceInstance) {
        return new SpringCloudCommandRouter(client, localServiceInstance, new AnnotationRoutingStrategy());
    }

    @Bean
    @Primary
    @Qualifier("springCloudConnector")
    public SpringHttpCommandBusConnector connector() {
        return new SpringHttpCommandBusConnector(new SimpleCommandBus(), new RestTemplate(), new JacksonSerializer());
    }

    @Bean
    @Primary
    @Qualifier("distributedBus")
    public DistributedCommandBus springCloudDistributedCommandBus(@Qualifier("springCloudRouter") CommandRouter router) {
        return new DistributedCommandBus(router, connector());
    }

    @Bean
    @Primary
    public AggregateFactory<CustomerAggregate> aggregateFactory(){
        return new GenericAggregateFactory<CustomerAggregate>(CustomerAggregate.class);
    }

    @Bean
    @Primary
    public EventCountSnapshotTriggerDefinition countSnapshotTriggerDefinition(){
        return new EventCountSnapshotTriggerDefinition(snapShotter(), 3);
    }

    @Bean
    @Primary
    public Snapshotter snapShotter(){
        return new AggregateSnapshotter(eventStore(), aggregateFactory());
    }

    @Bean
    @Primary
    public EventSourcingRepository<CustomerAggregate> customerAggregateRepository(){
        return new EventSourcingRepository<>(aggregateFactory(), eventStore(), countSnapshotTriggerDefinition());
    }

    @Bean(name = "axonMongoTemplate")
    public MongoTemplate axonMongoTemplate() {
        return new DefaultMongoTemplate(mongoClient(), mongoDbName)
            .withDomainEventsCollection(eventsCollectionName)
            .withSnapshotCollection(snapshotCollectionName)
            .withSagasCollection(sagaCollectionName);
    }

    @Bean
    public MongoClient mongoClient() {
        MongoFactory mongoFactory = new MongoFactory();
        mongoFactory.setMongoAddresses(Arrays.asList(new ServerAddress(mongoUrl)));
        return mongoFactory.createMongo();
    }

    @Bean
    @Primary
    public MongoEventStorageEngine engine() {
        return new MongoEventStorageEngine(new JacksonSerializer(), null, axonMongoTemplate(), new DocumentPerEventStorageStrategy());
    }

    @Bean
    @Primary
    public EventStore eventStore() {
        return new EmbeddedEventStore(engine());
    }
}

А вот и мой агрегатный класс с обработчиками команд:

@Aggregate(repository = "customerAggregateRepository")
public class CustomerAggregate {
    Logger logger = LoggerFactory.getLogger(this.getClass());

    @AggregateIdentifier
    private String id;
    private String firstName;
    private String lastName;
    private String email;

    private CustomerAggregate() {}

    public String getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public String getEmail() {
        return email;
    }

    @CommandHandler
    public CustomerAggregate(CreateCustomer cmd) {
        logger.debug("Received creation command: " + cmd.toString());
        apply(new CustomerCreated(cmd.getId(),cmd.getFirstName(),cmd.getLastName(), cmd.getEmail()));
    }

    @CommandHandler
    public void on(UpdateCustomer cmd) {
        logger.debug("Received update command: " + cmd.toString());
        apply(new CustomerUpdated(this.id,cmd.getFirstName(),cmd.getLastName(), cmd.getEmail()));
    }

    @CommandHandler
    public void on(UpdateCustomerEmail cmd) {
        logger.debug("Received update command for existing customer: " + cmd.toString());
        apply(new CustomerUpdated(cmd.getId(), this.firstName, this.lastName, cmd.getEmail()));
    }

    // Various event handlers...
}

Любая помощь горячо приветствуется.

Важно понимать, что механизму обнаружения требуется время для обнаружения узлов. На самом деле это может занять до 1 минуты. Кроме того, похоже, что здесь много настроек. Если вы используете загрузку Spring, подумайте об использовании распределенного стартера и позвольте Axon автоматически настраивать все за вас.

Allard 14.09.2018 00:07

Не могли бы вы рассказать, какую реализацию Spring Cloud Discovery вы используете? Это может изменить ответ, который я хотел бы дать по этому вопросу. Кроме того, я думаю, что у @allard есть веская точка зрения. Постарайтесь максимально использовать автоконфигурацию, предоставляемую фреймворком, это должно упростить вам жизнь.

Steven 14.09.2018 10:41

Аллард, я подумал, что это может быть так, поэтому я протестировал множество различных сценариев, включая один экземпляр приложения. В нескольких тестах я ждал продолжительное время и подтвердил, что служба была зарегистрирована на сервере eureka, который я использовал только для получения этого сообщения. Вы поднимаете хороший вопрос, что я должен попытаться использовать автоконфигурацию из компонентов аксона. Фактически, это могло быть всей моей проблемой.

Charlie Thomas 15.09.2018 14:59

Стивен, я использую Эврика.

Charlie Thomas 15.09.2018 15:00
0
4
695
0

Другие вопросы по теме