Multitenant Extension TargetTenantResolver


I’m playing around and testing the multitenancy extension and am running into something I’m not sure is intend or not.

Should events be split between the different contexts if setup correctly? Currently they are all in the default context and none of the events can be found in the their corresponding context in the AxonServer dashboard.

From what I’ve read in the limited documentation found I can either attach the tenantId to the metadata or use a customTargetTenantResolver to tell it where to look for the tenantId. I’ve tried both version and can see the tenantId in the metadata.

(This is all test data and test ids)

I’ve setup a single node with the default replication groups (_admin, default) and using the CreateContextRequest builder I created several tenants (based on CreateTenantService that all works fine and the TenantConnectPredicate works fine and returns the tenants.


Am i missing some step somewhere or is this intended?


Did you disable the meta data helper first?

It should be disabled by adding property: axon.multi-tenancy.use-metadata-helper=false

Then you can define a custom target tenant resolver.

For example:

public TargetTenantResolver<Message<?>> targetTenantResolver() {
    return (message, tenants) ->
          ((TenantAwareMessage) message.getPayload()).getTenant()

TenantAwareMessage does not exist, its just example where all of your messages would implement TenantAwareMessage interface so you can retrieve tenant from the payload.

Also, there should be no way for messages to end up in default context unless they are specifically instructed to. Please check your configuration to see if you have references like axon.axonserver.context=default ?

Thanks for the quick response.

I tried using the metadata-helper and just putting the tenantId in the metadata and I tried disabling it and using a custom resolver.

I’ll check the configuration and report back.

So I’ve reset everything and tried again with a completely fresh build.

I set up the axon server to only have the _admin context and replication group. I then created a default replication group and created the tenant contexts and associated them with that replication group and that seemed to work.

Another question.
Is there a way to register a handler interceptor or something similar as I need to set the tenantId in order to access the correct MongoDB collection.

We used to use

    public void configureEventProcessing(Configurer configurer) {
        configurer.eventProcessing().registerDefaultHandlerInterceptor((Configuration,String) -> new EventHandlerInterceptor());


    public Object handle(UnitOfWork<? extends EventMessage<?>> unitOfWork, InterceptorChain interceptorChain) throws Exception {
        EventMessage<BaseEvent> event = (EventMessage<BaseEvent>) unitOfWork.getMessage();
        String tenantId = Optional.ofNullable(event.getPayload().getTenantId()).orElseThrow(Exception::new);
        return null;

but thats causing the error application context form a cycle

I’m guessing the multitenancy extension reference guide is still WIP as I’m getting not found when going to

There is no support for MongoDB currently, only for JPA.
To make Mongo DB work you need multitenant support from Mongo and Spring.
Quick google shows it’s possible and not hard to implement.

Tenant info is already attached to each transaction, and can be accessed via the thread local. No need for additional interceptors…

Take a look how JPA variant works.

There is no support for MongoDB currently, only for JPA.

Thats essentially only for event and token store right?

Quick google shows it’s possible and not hard to implement.

So we have something similar setup currently and are using @MessageHandlerInterceptor to grab the tenantId from the event and set a ThreadLocal string which then gets used in the mongoTemplate to select the database.

I’ve tried using TenantWrappedTransactionManager.getCurrentTenant().tenantId() to get the tenantId and set the database that way. This works fine for existing events but for new messages it always ends up being null. It is correctly hitting my custom TargetTenantResolver with the tenantId in the payload and the TenantDescriptor gets set but whenever I try to get it through TenantWrappedTransactionManager anywhere after that its always null.