package com.worktajm.config.liquibase; import javax.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.core.env.Environment; import org.springframework.core.task.TaskExecutor; import org.springframework.util.StopWatch; import com.worktajm.config.Constants; import liquibase.exception.LiquibaseException; import liquibase.integration.spring.SpringLiquibase; /** * Specific liquibase.integration.spring.SpringLiquibase that will update the database asynchronously. * <p> * By default, this asynchronous version only works when using the "dev" profile.<br/> * The standard liquibase.integration.spring.SpringLiquibase starts Liquibase in the current thread: * <ul> * <li>This is needed if you want to do some database requests at startup</li> * <li>This ensure that the database is ready when the application starts</li> * </ul> * But as this is a rather slow process, we use this asynchronous version to speed up our start-up time: * <ul> * <li>On a recent MacBook Pro, start-up time is down from 14 seconds to 8 seconds</li> * <li>In production, this can help your application run on platforms like Heroku, where it must start/restart very quickly</li> * </ul> * </p> */ public class AsyncSpringLiquibase extends SpringLiquibase { private final Logger log = LoggerFactory.getLogger(AsyncSpringLiquibase.class); @Inject @Qualifier("taskExecutor") private TaskExecutor taskExecutor; @Inject private Environment env; @Override public void afterPropertiesSet() throws LiquibaseException { if (env.acceptsProfiles(Constants.SPRING_PROFILE_DEVELOPMENT, Constants.SPRING_PROFILE_HEROKU)) { taskExecutor.execute(() -> { try { log.warn("Starting Liquibase asynchronously, your database might not be ready at startup!"); initDb(); } catch (LiquibaseException e) { log.error("Liquibase could not start correctly, your database is NOT ready: {}", e.getMessage(), e); } }); } else { log.debug("Starting Liquibase synchronously"); initDb(); } } protected void initDb() throws LiquibaseException { StopWatch watch = new StopWatch(); watch.start(); super.afterPropertiesSet(); watch.stop(); log.debug("Started Liquibase in {} ms", watch.getTotalTimeMillis()); } }