Getting tenant Id as null from 'TenantAwareDataSource' in multi tenancy mode

When we configure flowable in multi-tenant multiple database mode.

@Override
public ProcessEngine buildProcessEngine() {
    
    setupTenantInfoHolder();
    MultiSchemaMultiTenantProcessEngineConfiguration config = new MultiSchemaMultiTenantProcessEngineConfiguration(this.tenantInfoHolder);     
    config.setDatabaseType(MultiSchemaMultiTenantProcessEngineConfiguration.DATABASE_TYPE_MSSQL);	config.setDatabaseSchemaUpdate(MultiSchemaMultiTenantProcessEngineConfiguration.DB_SCHEMA_UPDATE_DROP_CREATE);
 	
 	config.setAsyncExecutorActivate(true);
 	config.setDisableIdmEngine(true);
 	config.setAsyncExecutor(new SharedExecutorServiceAsyncExecutor(this.tenantInfoHolder));
	
 	config.registerTenant("tenant1", createDataSource("jdbc:sqlserver://localhost:1433", "tenant1", "sa", "pwd"));
 	ProcessEngine processEngine = config.buildProcessEngine();
	
    ProcessEngines.setInitialized(true);
    enginesBuild.add(processEngine.getName());
    return processEngine;
}

public void setupTenantInfoHolder() {
    DummyTenantInfoHolder tenantInfoHolder = new DummyTenantInfoHolder();
    tenantInfoHolder.addTenant("tenant1");
    tenantInfoHolder.addUser("tenant1", "user1");
    this.tenantInfoHolder = tenantInfoHolder;
}

private DataSource createDataSource(String jdbcUrl, String dbName, String jdbcUsername, String jdbcPassword) {
	      SQLServerDataSource ds = new SQLServerDataSource();
	     ds.setURL(jdbcUrl);
	     ds.setDatabaseName(dbName);
	     ds.setUser(jdbcUsername);
	     ds.setPassword(jdbcPassword);
	     return ds;
	}

We are getting Could not find a dataSource for tenant null.

Caused by: org.flowable.common.engine.api.FlowableException: Could not find a dataSource for tenant null
	at org.flowable.common.engine.impl.cfg.multitenant.TenantAwareDataSource.getCurrentDataSource(TenantAwareDataSource.java:68) ~[classes/:?]
	at org.flowable.common.engine.impl.cfg.multitenant.TenantAwareDataSource.getConnection(TenantAwareDataSource.java:56) ~[classes/:?]
	at org.apache.ibatis.transaction.jdbc.JdbcTransaction.openConnection(JdbcTransaction.java:138) ~[mybatis-3.5.2.jar:3.5.2]
	at org.apache.ibatis.transaction.jdbc.JdbcTransaction.getConnection(JdbcTransaction.java:60) ~[mybatis-3.5.2.jar:3.5.2]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.getConnection(DefaultSqlSession.java:297) ~[mybatis-3.5.2.jar:3.5.2]
	at org.flowable.common.engine.impl.db.DbSqlSessionFactory.openSession(DbSqlSessionFactory.java:96) ~[classes/:?]
	at org.flowable.common.engine.impl.interceptor.CommandContext.getSession(CommandContext.java:245) ~[classes/:?]
	at org.flowable.common.engine.impl.cfg.standalone.StandaloneMybatisTransactionContext.<init>(StandaloneMybatisTransactionContext.java:48) ~[classes/:?]
	at org.flowable.common.engine.impl.cfg.standalone.StandaloneMybatisTransactionContextFactory.openTransactionContext(StandaloneMybatisTransactionContextFactory.java:26) ~[classes/:?]
	at org.flowable.common.engine.impl.interceptor.TransactionContextInterceptor.execute(TransactionContextInterceptor.java:47) ~[classes/:?]
	at org.flowable.common.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:72) ~[classes/:?]
	at org.flowable.common.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:30) ~[classes/:?]
	at org.flowable.common.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:56) ~[classes/:?]
	at org.flowable.common.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:51) ~[classes/:?]
	at org.flowable.common.engine.impl.query.AbstractQuery.list(AbstractQuery.java:117) ~[classes/:?]
	at org.flowable.rest.conf.BootstrapConfiguration.initDemoProcessDefinitions(BootstrapConfiguration.java:146) ~[classes/:?]
	at org.flowable.rest.conf.BootstrapConfiguration.lambda$1(BootstrapConfiguration.java:80) ~[classes/:?]
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:781) ~[spring-boot-2.1.9.RELEASE.jar:2.1.9.RELEASE]
	... 10 more

Even though tenant Id is set, we are getting ‘tenantInfoHolder.getCurrentTenantId()’ as null from TenantAwareDataSource.getCurrentDataSource. It is calling multiple times, at last, we are getting a ‘null’ value. Could you please help in this to resolve this issue.Preformatted text

Looking at the stacktrace, it looks like you’re trying to change the Flowable REST application:

at org.flowable.rest.conf

This application does a demo setup on bootup by default, however it doesn’t know which tenant to create the demo data for. Disabling the demo setup on boot will fix this, however the Flowable REST app hasn’t been tested with multi-schema setup so there could be other things not working.

Thank you @joram. By disabling the demo setup it is working fine.

After this configuration setup, When we perform any tenant operation do we need to set this tenantId to ‘tenantInfoFolder’ currentTenantId.

Hi @HarishArawala @joram I am trying to do the same setup. Multi tenant engine with rest api.

I am able to setup the engine but I am not able to get the rest end points. I am getting 404.

This is my setup

package com.pc.test;
@SpringBootApplication
public class WorkflowApplication {
        public static void main(String[] args) {
                  SpringApplication.run(WorkflowApplication.class, args);
       }
}

Maven
`

    <dependency>
		<groupId>org.flowable</groupId>
		<artifactId>flowable-spring-boot-starter-basic</artifactId>
		<version>6.5.0</version>
	</dependency>

`
Engine configuration is same as yours. I see engine is running but not able to access any end points.

`

	@Bean
public MultiSchemaMultiTenantProcessEngineConfiguration processEngineConfigurationImpl() {
	BankOSTenantHolder tenantInfoHolder= new BankOSTenantHolder();
	tenantInfoHolder.addTenant(tenants);
          MultiSchemaMultiTenantProcessEngineConfiguration config= new MultiSchemaMultiTenantProcessEngineConfiguration(tenantInfoHolder);
	
	config.setDatabaseType(MultiSchemaMultiTenantProcessEngineConfiguration.DATABASE_TYPE_MYSQL);
    config.setDatabaseSchemaUpdate(MultiSchemaMultiTenantProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
    config.setAsyncExecutorActivate(true);
    config.setDisableIdmEngine(true);
    config.setDisableEventRegistry(true);

    if (sharedExecutor) {
        config.setAsyncExecutor(new SharedExecutorServiceAsyncExecutor(tenantInfoHolder));
    } else {
        config.setAsyncExecutor(new ExecutorPerTenantAsyncExecutor(tenantInfoHolder));
    }
    return config;
}

@Bean(name="processEngine")
public ProcessEngine buildProcessEngine(MultiSchemaMultiTenantProcessEngineConfiguration config) {
	
    
    for (String tenant : tenants) {
    	config.registerTenant(tenant,createDataSource(tenant));
	}

    return config.buildProcessEngine();
}

`

I tried adding “org.flowable” also in component scan but id did not help. I started getting error.
Caused by: java.lang.ClassNotFoundException: org.flowable.common.rest.exception.BaseExceptionHandlerAdvice

Any pointers will be appreciated.

Thanks.

Hey @prashant,

I would suggest reading Building your own Flowable Spring Boot application blog post and checking out our spring-boot example.

The reason why you are not seeing the REST APIs is because you do not have the needed dependencies on the classpath.

You need:

<dependency>
    <groupId>org.flowable</groupId>
    <artifactId>flowable-spring-boot-starter-process-rest</artifactId>
    <version>6.5.0</version>
</dependency>

in order to have the rest APIs for the process engine available

I have added this also to my dependency

 <artifactId>flowable-spring-boot-starter-process-rest</artifactId>

I figured out the issue. It is with component scan.

I have to add “org.flowable.rest” in my component scan.

    ComponentScan({ 
          "com.pc.test.workflowtest",
           "org.flowable.rest"
     })

Also I had to provide beans for

@Bean
public ObjectMapper modelMapper() {
	return new ObjectMapper();
}


@Bean
public RestResponseFactory restResponseFactory(ObjectMapper objectMapper) {
	return new RestResponseFactory(objectMapper);
}

@joram, I am getting similar exception and I am not using flowable rest

org.flowable.common.engine.api.FlowableException: Could not find a dataSource for tenant null
at org.flowable.common.engine.impl.cfg.multitenant.TenantAwareDataSource.getCurrentDataSource(TenantAwareDataSource.java:68) ~[flowable-engine-common-6.5.0.jar:6.5.0]
at org.flowable.common.engine.impl.cfg.multitenant.TenantAwareDataSource.getConnection(TenantAwareDataSource.java:56) ~[flowable-engine-common-6.5.0.jar:6.5.0]
at org.apache.ibatis.transaction.jdbc.JdbcTransaction.openConnection(JdbcTransaction.java:138) ~[mybatis-3.5.3.jar:3.5.3]
at org.apache.ibatis.transaction.jdbc.JdbcTransaction.getConnection(JdbcTransaction.java:60) ~[mybatis-3.5.3.jar:3.5.3]
at org.apache.ibatis.session.defaults.DefaultSqlSession.getConnection(DefaultSqlSession.java:297) ~[mybatis-3.5.3.jar:3.5.3]
at org.flowable.common.engine.impl.db.DbSqlSessionFactory.openSession(DbSqlSessionFactory.java:96) ~[flowable-engine-common-6.5.0.jar:6.5.0]
at org.flowable.common.engine.impl.interceptor.CommandContext.getSession(CommandContext.java:246) ~[flowable-engine-common-6.5.0.jar:6.5.0]
at org.flowable.common.engine.impl.cfg.standalone.StandaloneMybatisTransactionContext.(StandaloneMybatisTransactionContext.java:48) ~[flowable-engine-common-6.5.0.jar:6.5.0]
at org.flowable.common.engine.impl.cfg.standalone.StandaloneMybatisTransactionContextFactory.openTransactionContext(StandaloneMybatisTransactionContextFactory.java:26) ~[flowable-engine-common-6.5.0.jar:6.5.0]
at org.flowable.common.engine.impl.interceptor.TransactionContextInterceptor.execute(TransactionContextInterceptor.java:47) ~[flowable-engine-common-6.5.0.jar:6.5.0]
at org.flowable.common.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:72) ~[flowable-engine-common-6.5.0.jar:6.5.0]
at org.flowable.common.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:30) ~[flowable-engine-common-6.5.0.jar:6.5.0]
at org.flowable.common.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:56) ~[flowable-engine-common-6.5.0.jar:6.5.0]
at org.flowable.common.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:51) ~[flowable-engine-common-6.5.0.jar:6.5.0]
at org.flowable.engine.impl.RuntimeServiceImpl.startProcessInstance(RuntimeServiceImpl.java:732) ~[flowable-engine-6.5.0.jar:6.5.0]
at org.flowable.engine.impl.runtime.ProcessInstanceBuilderImpl.start(ProcessInstanceBuilderImpl.java:205) ~[flowable-engine-6.5.0.jar:6.5.0]
at com.swapstech.galaxy.workflow.service.WorkFlowServiceImpl.startWorkFlowAsync(WorkFlowServiceImpl.java:51) ~[classes/:na]
at com.swapstech.galaxy.workflow.service.WorkFlowServiceImpl$$FastClassBySpringCGLIB$$6873dbe7.invoke() ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_181]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_181]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_181]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_181]

Here is the code I am invoking it

processInstance = processEngine.getRuntimeService().createProcessInstanceBuilder()
.variables(workFlowModelMap)
.processDefinitionKey(processInstanceKey)
.predefineProcessInstanceId(processInstId)
.tenantId(tenant)
.start();

My engine configuration

@Bean
public MultiSchemaMultiTenantProcessEngineConfiguration processEngineConfigurationImpl() {
BankOSTenantHolder tenantInfoHolder= new BankOSTenantHolder();
tenantInfoHolder.addTenant(tenants);

	MultiSchemaMultiTenantProcessEngineConfiguration config= new MultiSchemaMultiTenantProcessEngineConfiguration(tenantInfoHolder);
	
	config.setDatabaseType(MultiSchemaMultiTenantProcessEngineConfiguration.DATABASE_TYPE_MYSQL);
    config.setDatabaseSchemaUpdate(MultiSchemaMultiTenantProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
    config.setAsyncExecutorActivate(true);
    config.setDisableIdmEngine(true);
    config.setDisableEventRegistry(true);
    config.setJpaEntityManagerFactory(localContainerEntityManagerFactoryBean.getObject());

    if (sharedExecutor) {
        config.setAsyncExecutor(new SharedExecutorServiceAsyncExecutor(tenantInfoHolder));
    } else {
        config.setAsyncExecutor(new ExecutorPerTenantAsyncExecutor(tenantInfoHolder));
    }
    return config;
}

@Bean
public ProcessEngine buildProcessEngine(MultiSchemaMultiTenantProcessEngineConfiguration config) {
for (String tenant : tenants) {
config.registerTenant(tenant,createDataSource(tenant));
}
return config.buildProcessEngine();
}