Secondary DataSource in existing Spring boot Application throwing ProcessEngineException

Hi everyone,

We’re having trouble getting a basic sample of the camunda engine to work in our spring boot application. We want to use a secondary datasource for camunda in a multi tenant environment with a single process engine. We have been following the documentation for the Process Engine Configuration and we have created an implementation of the CamundaDatasourceConfiguration interface.

@Configuration
public class CustomCamundaDatasourceConfig implements CamundaDatasourceConfiguration {

	@Bean(name="camundaBpmDataSource")
	public DataSource secondaryDataSource() {
		DataSourceBuilder builder = DataSourceBuilder.create();
		builder.url("jdbc:postgresql://localhost:5432/camunda?currentSchema=camunda");
		builder.username("REMOVED");
		return builder.build();
	}
	
	@Bean(name="camundaBpmTransactionManager")
	public PlatformTransactionManager camundaTransactionManager(@Qualifier("camundaBpmDataSource") DataSource dataSource) {
	  return new DataSourceTransactionManager(dataSource);
	}
}

We have also created a sample app to remove all possible causes on our end. A simple spring application only with the necessary dependencies for camunda and our postgres datasource.

The main goal is to have the camunda processes in a single schema while our own data is still stored in a schema per tenant. But we cannot get camunda to work with the CamundaDatasourceConfiguration implementation. The PlatformTransactionManager never gets called and the SpringTransactionsProcessEngineConfiguration always throws an error

 org.camunda.bpm.engine.ProcessEngineException: transactionManager is required property for SpringProcessEngineConfiguration

What are we missing?

Hi,

We did this a few years ago so sorry if this is a bit rusty as digging back in the code for this. So we set creates the config as follows

@Configuration
public class WorkflowConfiguration {

  @Bean
  @ConfigurationProperties("spring.datasource.first")
  @Primary
  public DataSourceProperties dataSourceProperties() {
    return new DataSourceProperties();
  }


  @Bean
  @ConfigurationProperties("spring.datasource.second")
  public DataSourceProperties dataSourceProperties2() {
    return new DataSourceProperties();
  }


  @Bean(name = "noncamundaDataSource")
  @ConfigurationProperties("spring.datasource.first")
  @Primary
  public DataSource firstDataSource(DataSourceProperties properties) {
    return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
  }


  @Bean(name = "camundaBpmDataSource")
  @ConfigurationProperties("spring.datasource.second")
  public DataSource secondDataSource(@Qualifier("dataSourceProperties2") DataSourceProperties properties) {
    return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
  }
}
### non camunda database
spring.datasource.first:
  url: jdbc:mysql://address=(host=localhost)(protocol=tcp)(nullNamePatternMatchesAll=true)(cacheCallableStmts=true)(callableStmtCacheSize=500)(useSSL=false)(noAccessToProcedureBodies=true)(port=3306)/noncamunda
  username: user
  password: password
  connection-test-query: select 1;
  maximum-pool-size: 8
  minimum-idle: 1
  max-lifetime: 1800000
  pool-name: noncamundaPool


### camunda database
spring.datasource.second:
  url: jdbc:mysql://address=(host=localhost)(protocol=tcp)(nullNamePatternMatchesAll=true)(cacheCallableStmts=true)(callableStmtCacheSize=500)(useSSL=false)(noAccessToProcedureBodies=true)(port=3306)/camunda
  username: user
  password: password
  connection-test-query: select 1;
  maximum-pool-size: 8
  minimum-idle: 1
  max-lifetime: 1800000
  pool-name: camundaPool

We did move away from the multi datasource though as we found issues with transactions inconsistency with rollbacks between the 2 datasources.
Instead we used the same datasource but still kept camunda in a separate schema in the same database.

Hope that helps

Hey matt,
thanks for your reply.

Did you implement a MultiTenantConnectionProvider for the different schemas? It seems that we would probably run into the same inconsistencies as you did with multiple datasources.

Hi,
No we didn’t implement the MultiTenantConnectionProvider. We did the following (hopefully didn’t miss anything out) . Also not sure if this will be suitable for all cases as all our interactions with the non camunda schema is through stored procedures.

new config in yaml, so we can specify the schemas being used

# Database prefixs
db:
  noncamunda.prefix: noncamunda
  camunda.prefix: camunda

### Database
spring.datasource.first:
  url: jdbc:mysql://address=(host=localhost)(protocol=tcp)(nullNamePatternMatchesAll=true)(cacheCallableStmts=true)(callableStmtCacheSize=500)(useSSL=false)(noAccessToProcedureBodies=true)(port=3306)/camunda
  username: user
  password: password
  connection-test-query: select 1;
  maximum-pool-size: 8
  minimum-idle: 1
  max-lifetime: 1800000
  pool-name: dbPool

Updated bean config

@Configuration
public class WorkflowConfiguration {
  @Bean
  @ConfigurationProperties("spring.datasource.first")
  @Primary
  public DataSourceProperties dataSourceProperties() {
    return new DataSourceProperties();
  }

  @Bean(name = "camundaBpmDataSource")
  @ConfigurationProperties("spring.datasource.first")
  @Primary
  public DataSource firstDataSource(DataSourceProperties properties) {
    return properties.initializeDataSourceBuilder()
        .type(HikariDataSource.class).build();
  }
}

Ensuring the correct schema and table prefix in camunda

@Component
@Order(Ordering.DEFAULT_ORDER + 1)
public class WorkflowSpringProcessEngineConfiguration extends AbstractCamundaConfiguration {
  @Value("${db.camunda.prefix:#{null}}")
  private String prefix;

  @Override
  public void preInit(SpringProcessEngineConfiguration config) {
    if (prefix != null && !prefix.isEmpty()) {
      config.setDatabaseTablePrefix(prefix + ".");
      config.setDatabaseSchema(prefix);
    }
  }
}

And example of calling our stored proc

connection.prepareCall("CALL " + prefix + ".a_stored_procedure(?,?)");