Distributed command bus not registering local Aggregate CommandHandlers [Axon3.4.3]

After switching to the distributed command bus, the local aggregate commandhandlers aren’t registered.
I keep getting the “No node known to accept” error.
I’ve come across https://groups.google.com/forum/#!topic/axonframework/BXUFcSZEuoI but according to this, the issue should’ve been fixed since 3.0.4

my local service’s config looks like this:

@Configuration
@AutoConfigureAfter(AxonAutoConfiguration.class)
public class OrchestratorConfig {

    @Autowired
    private Registration registration;

    private RestTemplate restTemplate = new RestTemplate();

    @Bean
    public CommandBusConnector springHttpCommandBusConnector(@Qualifier("localSegment") CommandBus localSegment,
                                                             Serializer serializer) {
        return new SpringHttpCommandBusConnector(localSegment, restTemplate, serializer);
    }

    @Bean
    public CommandRouter springCloudCommandRouter(DiscoveryClient discoveryClient) {
        return new SpringCloudCommandRouter(discoveryClient, registration, new AnnotationRoutingStrategy());
    }

    @Bean
    @Primary
    public DistributedCommandBus springCloudDistributedCommandBus(CommandRouter commandRouter,
                                                                  CommandBusConnector springHttpCommandBusConnector) {
        return new DistributedCommandBus(commandRouter, springHttpCommandBusConnector);
    }

}

my Aggregate

@Aggregate
@Slf4j
@Data
@NoArgsConstructor
public class CreateCurrencyAggregate {

    @AggregateIdentifier
    private String createCurrencyId;

    @CommandHandler
    public CreateCurrencyAggregate(CreateCurrencyCommand command) {
        log.info("starting create currency");
        Assert.notNull(command.getId(), "CreateCurrencyCommand must have an id");
        Assert.hasLength(command.getId(), "CreateCurrencyCommand id cannot be an empty String");
        this.createCurrencyId = command.getId();
        apply(CreateCurrencyEvent.builder()
                .id(command.getId())
                .payload(command.getPayload())
                .build());
    }

    @CommandHandler
    public void handle(DalCreatedCommand command) {
        log.info("returning from dal service");
        Assert.notNull(command.getId(), "DalCreatedCommand must have an id");
        apply(DalCurrencyCreatedEvent.builder()
                .transactionId(command.getId())
                .build());
    }

    @CommandHandler
    public void handle(As400CreatedCommand command) {
        log.info("returning from as400 service");
        Assert.notNull(command.getId(), "As400CreatedCommand must have an id");
        apply(As400CurrencyCreatedEvent.builder()
                .transactionId(command.getId())
                .build());
    }

}

dependencies

Hi Jeroen,

In Axon Framework, the SpringCloudCommandRouter is in charge of notifying all the discovered Service Instances of the commands a given instance can handle.
It does so, by updating the Metadata of a Service Instance.

From your snippets, I see you’re using Eureka as the Discovery Service.
As far as I know is correctly capable of adjusting the metadata of your nodes in the set up.
I also believe the Eureka dashboard is capable of showing the metadata any service instance has stored in place.

Would you mind verifying whether you see fields like the “loadFactor”, “serializedCommandFilter” and “serializedCommandFilterClassName” in the metadata of your Axon Service Instance?

Cheers,
Steven

Hey Steven,

I’ve noticed this was happening when using openfeign in combination with axon-spring.
In the meantime I’ve updated to axon4.1.1 to see if it was still an issue and it still is.

I’ve verified this by using a restTemplate directly instead of openFeign to execute some rest calls and it works fine,
however as soon as I include openFeign back into the project I get the same error namely: “NoHandlerForCommandException(No node known to accept…”

axonconfig:

@Configuration
public class AxonConfig {
    @Autowired
    private Registration registration;

    @Autowired
    @Qualifier("axonDatasource")
    private DataSource dataSource;

    @Bean
    public CommandBusConnector springHttpCommandBusConnector(@Qualifier("localSegment") CommandBus localSegment,
                                                             Serializer serializer) {
        return SpringHttpCommandBusConnector.builder()
                .localCommandBus(localSegment)
                .restOperations(new RestTemplate())
                .serializer(serializer)
                .build();
    }

    @Bean
    @Primary
    public CommandRouter springCloudCommandRouter(DiscoveryClient discoveryClient) {
        return SpringCloudCommandRouter.builder()
                .discoveryClient(discoveryClient)
                .localServiceInstance(registration)
                .routingStrategy(new AnnotationRoutingStrategy())
                .build();
    }

    @Bean
    @Primary
    public DistributedCommandBus springCloudDistributedCommandBus(CommandRouter commandRouter,
                                                                  CommandBusConnector commandBusConnector) {
        return DistributedCommandBus.builder()
                .commandRouter(commandRouter)
                .connector(commandBusConnector)
                .build();
    }

    @Bean
    @Primary
    public SpringDataSourceConnectionProvider springDataSourceConnectionProvider() {
        return new SpringDataSourceConnectionProvider(dataSource);
    }

I have tested this with FINCHLEY and GREENWICH releases of spring-cloud and the result stays the same, the metadata isn’t updated and I receive no warnings or errors.

Hi Jeroen,

Firstly, I’d assume OpenFeign shouldn’t pose any issue for the Spring Cloud Command Router solution.
And, as you’ve updated to 4.1.1, does that also mean you’ve moved over to using the Spring Cloud Extension dependency?
As a side note, all big dependencies Axon Framework had which we did not view as mandatory to be pulled in have deliberately moved into their own repository as of Axon 4; hence why I am pointing this out.

Secondly, your configuration looks fine too me by the way, which doesn’t make it easier to figure out what the problem is.
What however is no clear for me from your response, is whether you’ve checked the Eureka dashboard for metadata contents yes/no.

At this stage I think we can suggest three approaches:

  1. Debug suggestions through the SpringCloudCommandRouter to understand what’s failing.
  2. Sharing a test repository with us, so that we can debug for your.
  3. Replace the SpringCloudCommandRouter for the SpringCloudHttpBackupCommandRouter.
    For option one, I’d drop a break point in the SpringCloudCommandRouter#updateMembership(int, CommandMessageFilter) on line 149.
    This method should be called consecutively on start up, as the updateMembership function is what’s called to register every command handler in your application.
    From here, you can see whether the code correctly updates the local Service Instance, thus whether it adds it’s own metadata with the command filter.

After updating itself towards the cluster, it will check the other Service Instances for the commands they can handle.

More specifically, this is done on specific Spring Events firing, which lead to the private updateMemberships method.

In here, it will create a list of all the ServiceInstances it can find (on line 213).

I’d recommend to check whether this list contains the expected applications you have running.

If not, then there is an issue with your Eureka set up, and switching over to the SpringCloudHttpBackupCommandRouter (my third suggestion) will not resolve anything.

If the above description is insufficient guidance to understand what is going on, we could go for the second approach.

However, I hope that’ll not be necessary of course.

Let’s try to resolve your problem Jeroen!

Cheers,
Steven