Issues when configuring CommandGateway with RetryScheduler

I have an application that uses Axon tracing extension. When used with SpringBoot, the tracing extension auto-configures its own TracingCommandGateway via TracingAutoConfiguration.tracingCommandGateway().

When I want to add a RetryScheduler in the picture, it looks like the only way is to copy and modify configuration from TracingAutoConfiguration.tracingCommandGateway(). In addition, to support the usage of the axon.extension.tracing.enabled configuration property and the case when it is set to false, I also have to add configuration for DefaultCommandGateway. With all this, I ended with a configuration similar to the following:

  @ConditionalOnProperty(value = "axon.extension.tracing.enabled", havingValue = "false", matchIfMissing = false)
  @Bean
  CommandGateway defaultCommandGateway(CommandBus commandBus) {
    ScheduledExecutorService scheduledExecutorService = ... 
    RetryScheduler retryScheduler = ...

    CommandGateway defaultCommandGateway = DefaultCommandGateway
        .builder()
        .commandBus(commandBus)
        .retryScheduler(retryScheduler)
        .build()

    return defaultCommandGateway
  }

  @ConditionalOnProperty(value = "axon.extension.tracing.enabled", havingValue = "true", matchIfMissing = true)
  @Bean
  CommandGateway tracingCommandGateway(
      Tracer tracer, CommandBus commandBus, OpenTraceDispatchInterceptor openTraceDispatchInterceptor, OpenTraceHandlerInterceptor openTraceHandlerInterceptor,
      MessageTagBuilderService messageTagBuilderService)
  {
    ...
    ScheduledExecutorService scheduledExecutorService = ...
    RetryScheduler retryScheduler = ...

    CommandGateway commandGatewayDelegate = DefaultCommandGateway
        .builder()
        .commandBus(commandBus)
        .retryScheduler(retryScheduler)
        .build()

    TracingCommandGateway tracingCommandGateway = TracingCommandGateway
        .builder()
        .tracer(tracer)
        .delegateCommandGateway(commandGatewayDelegate)
        .messageTagBuilderService(messageTagBuilderService)
        .build()

    ...
    return tracingCommandGateway
  }

As you might guess, I’m not quite happy with such a setup :slight_smile: :

  • trying to add a RetryScheduler on the gateway requires rewriting the gateway config. Without RetryScheduler, my SpringBoot configuration is blissfully unaware of the gateway.
  • to support configuration above, I have to declare org.axonframework.extensions.tracing:axon-tracing-spring-boot-starter and io.opentracing.contrib:opentracing-spring-cloud-starter as compile dependencies. Without configuring RetryScheduler, they are declared as runtime only dependencies.
  • my Spring Boot configuration have to import all those classes from the tracing extension and opentracing library
  • my SpringBoot configuration has to deal with the fact that the user may turn off tracing

I’m not quite sure how this can be tackled (and if it is worth dealing with it at all). There are several possibilities, I guess:

  • extending CommandGateway interface with something like registerRetryScheduler() method. This will be quite a significant breaking change. However, it will allow custom registration of a RetryScheduler, for example, in ApplicationListener<ApplicationStartedEvent> Spring listener.
  • adding another interface, something like RetryableCommandGateway or RetrySchedulerSupport. Then gateway implementation can implement it at its own pace. In my case, it will require slight modification of both DefaultCommandGateway and TracingCommandGateway.
  • modifying DefaultCommandGateway and TracingCommandGateway Spring Boot auto-configuration where auto-configuration can check if RetryScheduler is available in the context, and if it is, register it on a gateway.

WDYT?

If I’m missing some alternative way for registering a RetryScheduler that is already present in the framework, please advise.

Tnx

Although sadly, I wouldn’t recommend anything different from what you’ve already done @dmurat.

At the core, I would want the Tracing solution to work differently from how it does right now. Adjusting the current implementation would, however, be a massive breaking change. On top of that, the Tracing API (which the extension is based on) is no longer in active development.

Instead, Open Tracing and Open Census have merged into Open Telemetry. This will require an entirely new approach altogether. Furthermore, this provides us an opportunity to adjust the approach and provide a friendlier API to the user (like you).

In all, I’d personally like to steer away from diving into a friendlier solution just yet, mainly because we need to investigate this new extension on our end anyhow. Hence, I hope that for the time being, you are okay with the solution as you have it right now, with the knowledge we will change this in the foreseeable future.

Giving the ease of configuring Axon in some other areas, I thought that I’m missing something.
And yes, I can live with the current solution as it is :grinning:

Tnx for the useful info about the roadmap.