Skip to content

Commit

Permalink
add detached mode for running H2 (DAT-17654) (#5929)
Browse files Browse the repository at this point in the history
  • Loading branch information
StevenMassaro committed Jun 17, 2024
1 parent c8edcf9 commit a4880f0
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Optional Args:
Default: 127.0.0.1
dbPort (Integer) Port to run h2 database on
Default: 9090
detached (Boolean) When set to true, Liquibase initiates the H2 database in a new thread without blocking, allowing use within the flow command. Regardless of the parameter setting, data stored in the H2 database is cleared when the JVM exits, such as at the end of the flow command.
Default: false
launchBrowser (Boolean) Whether to open a browser to the database's web interface
Default: true
password (String) Password to use for created h2 user
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.ArrayList;
import java.util.List;

public class StartH2CommandStep extends AbstractCommandStep {

Expand All @@ -18,6 +20,12 @@ public class StartH2CommandStep extends AbstractCommandStep {
public static final CommandArgumentDefinition<String> PASSWORD_ARG;
public static final CommandArgumentDefinition<Boolean> LAUNCH_BROWSER_ARG;

private static final CommandArgumentDefinition<Boolean> DETACHED;
/**
* List of threads that are running the H2 database. Used to stop them when the stopH2 command is run.
*/
public static final List<Thread> RUNNING_THREADS = new ArrayList<>();

static {
CommandBuilder builder = new CommandBuilder(COMMAND_NAME);
DB_PORT_ARG = builder.argument("dbPort", Integer.class)
Expand Down Expand Up @@ -50,6 +58,11 @@ public class StartH2CommandStep extends AbstractCommandStep {
.description("Whether to open a browser to the database's web interface")
.defaultValue(true)
.build();

DETACHED = builder.argument("detached", Boolean.class)
.description("When set to true, Liquibase initiates the H2 database in a new thread without blocking, allowing use within the flow command. Regardless of the parameter setting, data stored in the H2 database is cleared when the JVM exits, such as at the end of the flow command.")
.defaultValue(false)
.build();
}

@Override
Expand All @@ -74,39 +87,51 @@ public void run(CommandResultsBuilder resultsBuilder) throws Exception {
final String password = commandScope.getConfiguredValue(PASSWORD_ARG).getValue();
final Integer dbPort = commandScope.getConfiguredValue(DB_PORT_ARG).getValue();
final Integer webPort = commandScope.getConfiguredValue(WEB_PORT_ARG).getValue();
final Boolean detached = commandScope.getConfiguredValue(DETACHED).getValue();

Thread thread = new Thread(() -> {
try (Connection devConnection = DriverManager.getConnection("jdbc:h2:mem:dev", username, password);
Connection intConnection = DriverManager.getConnection("jdbc:h2:mem:integration", username, password)) {

startTcpServer(dbPort);

Object webServer = startWebServer(webPort);
String devUrl = createWebSession(devConnection, webServer, commandScope.getConfiguredValue(LAUNCH_BROWSER_ARG).getValue());
String intUrl = createWebSession(intConnection, webServer, false);

System.out.println("Connection Information:" + System.lineSeparator() +
" Dev database: " + System.lineSeparator() +
" JDBC URL: jdbc:h2:tcp://localhost:" + dbPort + "/mem:dev" + System.lineSeparator() +
" Username: " + username + System.lineSeparator() +
" Password: " + password + System.lineSeparator() +
" Integration database: " + System.lineSeparator() +
" JDBC URL: jdbc:h2:tcp://localhost:" + dbPort + "/mem:integration" + System.lineSeparator() +
" Username: " + username + System.lineSeparator() +
" Password: " + password + System.lineSeparator() +
"" + System.lineSeparator() +
"Opening Database Console in Browser..." + System.lineSeparator() +
" Dev Web URL: " + devUrl + System.lineSeparator() +
" Integration Web URL: " + intUrl + System.lineSeparator());


Runtime.getRuntime().addShutdownHook(new Thread(() -> {
Scope.getCurrentScope().getUI().sendMessage("Shutting down H2 database...");
}));

Thread.sleep(Long.MAX_VALUE);
} catch (Throwable e) {
e.printStackTrace();
Thread.currentThread().interrupt();
System.exit(-1);
}
});

try (Connection devConnection = DriverManager.getConnection("jdbc:h2:mem:dev", username, password);
Connection intConnection = DriverManager.getConnection("jdbc:h2:mem:integration", username, password)) {

startTcpServer(dbPort);

Object webServer = startWebServer(webPort);
String devUrl = createWebSession(devConnection, webServer, commandScope.getConfiguredValue(LAUNCH_BROWSER_ARG).getValue());
String intUrl = createWebSession(intConnection, webServer, false);

System.out.println("Connection Information:" + System.lineSeparator() +
" Dev database: " + System.lineSeparator() +
" JDBC URL: jdbc:h2:tcp://localhost:" + dbPort + "/mem:dev" + System.lineSeparator() +
" Username: " + username + System.lineSeparator() +
" Password: " + password + System.lineSeparator() +
" Integration database: " + System.lineSeparator() +
" JDBC URL: jdbc:h2:tcp://localhost:" + dbPort + "/mem:integration" + System.lineSeparator() +
" Username: " + username + System.lineSeparator() +
" Password: " + password + System.lineSeparator() +
"" + System.lineSeparator() +
"Opening Database Console in Browser..." + System.lineSeparator() +
" Dev Web URL: " + devUrl + System.lineSeparator() +
" Integration Web URL: " + intUrl + System.lineSeparator());


Runtime.getRuntime().addShutdownHook(new Thread(() -> Scope.getCurrentScope().getUI().sendMessage("Shutting down H2 database...")));
RUNNING_THREADS.add(thread);
thread.start();

Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
throw e;
} catch (Throwable e) {
e.printStackTrace();
System.exit(-1);
if (Boolean.FALSE.equals(detached)) {
thread.join();
RUNNING_THREADS.remove(thread);
}

resultsBuilder.addResult("statusCode", 0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package liquibase.command.core;

import liquibase.Scope;
import liquibase.command.AbstractCommandStep;
import liquibase.command.CommandDefinition;
import liquibase.command.CommandResultsBuilder;

import java.util.Iterator;

public class StopH2CommandStep extends AbstractCommandStep {

public static final String[] COMMAND_NAME = {"init", "stopH2"};

@Override
public String[][] defineCommandNames() {
return new String[][]{COMMAND_NAME};
}

@Override
public void adjustCommandDefinition(CommandDefinition commandDefinition) {
super.adjustCommandDefinition(commandDefinition);
commandDefinition.setHidden(true);
}

@Override
public void run(CommandResultsBuilder resultsBuilder) throws Exception {
for (Iterator<Thread> iterator = StartH2CommandStep.RUNNING_THREADS.iterator(); iterator.hasNext(); ) {
Thread runningThread = iterator.next();
try {
runningThread.interrupt();
iterator.remove();
} catch (Exception e) {
Scope.getCurrentScope().getLog(getClass()).warning("Error stopping H2 thread", e);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ liquibase.command.core.SnapshotCommandStep
liquibase.command.core.SnapshotReferenceCommandStep
liquibase.command.core.StartH2CommandStep
liquibase.command.core.StatusCommandStep
liquibase.command.core.StopH2CommandStep
liquibase.command.core.TagCommandStep
liquibase.command.core.TagExistsCommandStep
liquibase.command.core.UnexpectedChangesetsCommandStep
Expand Down

0 comments on commit a4880f0

Please sign in to comment.