Multitenancy Extension - multiplied command bus message handlers interceptors

MultiTenantCommandBus for each tenant registers AxonServerCommandBus

which uses localSegment (SimpleCommandBus) injected as a bean unlike it is in MultiTenantQueryBus where for each tenant registers AxonServerQueryBus which uses localSegment (SimpleQueryBus) created each time by the builder

The above causes that if we have some message handler interceptors e.g. for auth which is a common one and try to register it to MultiTenantCommandBus and MultiTenantQueryBus then for command bus this interceptor will be multiplied as many times as there are tenants and in query bus it will be just one (as expected).

The workaround for this is to register these interceptors for the command bus not for the MultiTenantCommandBus but for the localSegment directly (as there is a registered correlation one).

In general, having localSegment as a bean is good because we can easily override it (there was some workaround e.g. to disable transaction manager) but on the other hand, it causes an issue in multitenancy by multiplying the same interceptor many times in the chain which causes other issues.

Can you resolve it somehow - still want to have the option to have localsegment as bean but to not duplicate interceptors in chain?

@stefand

In kotlin it can be bypassed e.g. by delegating interfaces

class ExtendedMultiTenantCommandBus(
    private val localSegment: CommandBus,
    private val delegate: MultiTenantCommandBus
) : CommandBus by delegate,
    MultiTenantAwareComponent by delegate,
    MultiTenantDispatchInterceptorSupport<CommandMessage<*>, CommandBus> by delegate,
    MultiTenantHandlerInterceptorSupport<CommandMessage<*>, CommandBus> by delegate {

    override fun tenantSegments(): Map<TenantDescriptor, CommandBus> {
        return delegate.tenantSegments()
    }

    override fun registerDispatchInterceptor(dispatchInterceptor: MessageDispatchInterceptor<in CommandMessage<*>>): Registration {
        return delegate.registerDispatchInterceptor(dispatchInterceptor)
    }

    override fun registerHandlerInterceptor(handlerInterceptor: MessageHandlerInterceptor<in CommandMessage<*>>): Registration {
        localSegment.registerHandlerInterceptor(handlerInterceptor)

        return Registration { false }
    }
}

and BeanPostProcessor


@Component
class PropertySourcePostProcessor : BeanPostProcessor {
    private var localSegment: CommandBus? = null

    @Throws(BeansException::class)
    override fun postProcessBeforeInitialization(bean: Any, beanName: String): Any = (bean as? MultiTenantCommandBus)
        ?.run { localSegment?.let { ExtendedMultiTenantCommandBus(localSegment = it, delegate = bean) } } 
        ?: bean

    @Throws(BeansException::class)
    override fun postProcessAfterInitialization(bean: Any, beanName: String): Any = (bean as? SimpleCommandBus)
        ?.also { localSegment = bean }
        ?: bean
}