Liuibase.executor.ExecutorService is not threadsafe

We are running liquibase concurrently to patch multiple databases using the same migration file. The liquibase version is 3.10.0. The database is Azure Sql. The exception is thrown in liquibase.executor.ExecutorService.getExecutor (line 93). The reason is multiple threads try to populate the none-threadsafe HashMap for the same key. This should be easily fixed by using a ConncurrentHashMap.

public class ExecutorService {
    private static ExecutorService instance = new ExecutorService();
    private List<Executor> registry = new ArrayList<>();
    private Map<String, Executor> executors = new HashMap<>();

Below is the stack trace.

! java.util.ConcurrentModificationException: null
! at java.base/java.util.HashMap.computeIfAbsent(
! at liquibase.executor.ExecutorService.getExecutor(
[script-executor] Script completed with exit code: 1.
! at liquibase.database.AbstractJdbcDatabase.getConnectionSchemaName(
! at liquibase.database.AbstractJdbcDatabase.getDefaultSchemaName(
! at liquibase.changelog.ChangeLogParameters.<init>(
! at liquibase.Liquibase.<init>(
! at io.dropwizard.migrations.CloseableLiquibase.<init>(
! at io.dropwizard.migrations.CloseableLiquibaseWithClassPathMigrationsFile.<init>(
[go] Task status: failed, took: 43.334s
! at io.dropwizard.migrations.AbstractLiquibaseCommand.openLiquibase(
! at

Hey @jxz024000! Welcome to the Liquibase community.

Thanks for bringing this issue up. Would you mind logging this issue here?

Primary way to make change in the product is through our github project in the link above, or you can even make a PR and we’ll merge your code directly in! The forum here is primarily for discussion on topics.