mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2025-02-25 18:55:28 -06:00
Merge pull request #781 from nosqlbench/780-sporadic-buildtest-failures-gh-actions
Sporadic test failures w/ gh actions
This commit is contained in:
commit
eaefd9a1b2
14
.github/workflows/build.yml
vendored
14
.github/workflows/build.yml
vendored
@ -10,6 +10,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
name: checkout nosqlbench
|
name: checkout nosqlbench
|
||||||
|
|
||||||
- uses: actions/setup-java@v3
|
- uses: actions/setup-java@v3
|
||||||
name: setup java
|
name: setup java
|
||||||
with:
|
with:
|
||||||
@ -25,16 +26,19 @@ jobs:
|
|||||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||||
restore-keys: ${{ runner.os }}-m2
|
restore-keys: ${{ runner.os }}-m2
|
||||||
|
|
||||||
- name: mvn package
|
- name: mvn-package
|
||||||
run: mvn package
|
run: mvn package
|
||||||
|
|
||||||
- name: mvn verify
|
- name: mvn-verify
|
||||||
run: mvn verify
|
run: mvn verify
|
||||||
|
|
||||||
|
- name: Capture
|
||||||
|
if: success() || failure()
|
||||||
|
run: tar -cvf logfiles.tar [a-zA-Z]**/logs/*
|
||||||
|
|
||||||
- name: Archive Test Results
|
- name: Archive Test Results
|
||||||
if: always()
|
if: success() || failure()
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: test-results
|
name: test-results
|
||||||
path: |
|
path: logfiles.tar
|
||||||
[a-zA-Z]**/logs/*
|
|
||||||
|
@ -28,7 +28,7 @@ import java.util.Map;
|
|||||||
* Cause a blocking call to delay the initialization
|
* Cause a blocking call to delay the initialization
|
||||||
* of this owning operation for a number of milliseconds.
|
* of this owning operation for a number of milliseconds.
|
||||||
*/
|
*/
|
||||||
@Service(value= DiagTask.class,selector = "erroroncycle")
|
@Service(value = DiagTask.class, selector = "erroroncycle")
|
||||||
public class DiagTask_erroroncycle implements DiagTask {
|
public class DiagTask_erroroncycle implements DiagTask {
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
@ -36,21 +36,21 @@ public class DiagTask_erroroncycle implements DiagTask {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyConfig(NBConfiguration cfg) {
|
public void applyConfig(NBConfiguration cfg) {
|
||||||
this.name = cfg.get("name",String.class);
|
this.name = cfg.get("name", String.class);
|
||||||
error_on_cycle = cfg.get("erroroncycle",long.class);
|
error_on_cycle = cfg.get("erroroncycle", long.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NBConfigModel getConfigModel() {
|
public NBConfigModel getConfigModel() {
|
||||||
return ConfigModel.of(DiagTask_erroroncycle.class)
|
return ConfigModel.of(DiagTask_erroroncycle.class)
|
||||||
.add(Param.required("name",String.class))
|
.add(Param.required("name", String.class))
|
||||||
.add(Param.defaultTo("erroroncycle",1L))
|
.add(Param.defaultTo("erroroncycle", 1L))
|
||||||
.asReadOnly();
|
.asReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> apply(Long aLong, Map<String, Object> stringObjectMap) {
|
public Map<String, Object> apply(Long aLong, Map<String, Object> stringObjectMap) {
|
||||||
if (error_on_cycle==aLong) {
|
if (error_on_cycle == aLong) {
|
||||||
throw new RuntimeException("Diag was requested to stop on cycle " + error_on_cycle);
|
throw new RuntimeException("Diag was requested to stop on cycle " + error_on_cycle);
|
||||||
}
|
}
|
||||||
return Map.of();
|
return Map.of();
|
||||||
|
@ -63,10 +63,10 @@ import java.util.stream.Collectors;
|
|||||||
public class NBCLI implements Function<String[], Integer> {
|
public class NBCLI implements Function<String[], Integer> {
|
||||||
|
|
||||||
private static Logger logger;
|
private static Logger logger;
|
||||||
private static LoggerConfig loggerConfig;
|
private static final LoggerConfig loggerConfig;
|
||||||
private static int EXIT_OK = 0;
|
private static final int EXIT_OK = 0;
|
||||||
private static int EXIT_WARNING = 1;
|
private static final int EXIT_WARNING = 1;
|
||||||
private static int EXIT_ERROR = 2;
|
private static final int EXIT_ERROR = 2;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
loggerConfig = new LoggerConfig();
|
loggerConfig = new LoggerConfig();
|
||||||
@ -83,6 +83,7 @@ public class NBCLI implements Function<String[], Integer> {
|
|||||||
* Only call System.exit with the body of main. This is so that other scenario
|
* Only call System.exit with the body of main. This is so that other scenario
|
||||||
* invocations are handled functionally by {@link #apply(String[])}, which allows
|
* invocations are handled functionally by {@link #apply(String[])}, which allows
|
||||||
* for scenario encapsulation and concurrent testing.
|
* for scenario encapsulation and concurrent testing.
|
||||||
|
*
|
||||||
* @param args Command Line Args
|
* @param args Command Line Args
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
@ -91,15 +92,17 @@ public class NBCLI implements Function<String[], Integer> {
|
|||||||
int statusCode = cli.apply(args);
|
int statusCode = cli.apply(args);
|
||||||
System.exit(statusCode);
|
System.exit(statusCode);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
System.out.println("Not expected issue in main: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return null;
|
* return null;
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* public static void main(String[] args) {
|
* public static void main(String[] args) {
|
||||||
* @param strings
|
*
|
||||||
|
* @param args
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@ -114,10 +117,11 @@ public class NBCLI implements Function<String[], Integer> {
|
|||||||
|
|
||||||
if (arg.toLowerCase(Locale.ROOT).startsWith("-v") || (arg.toLowerCase(Locale.ROOT).equals("--show-stacktraces"))) {
|
if (arg.toLowerCase(Locale.ROOT).startsWith("-v") || (arg.toLowerCase(Locale.ROOT).equals("--show-stacktraces"))) {
|
||||||
showStackTraces = true;
|
showStackTraces = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String error = ScenarioErrorHandler.handle(e, showStackTraces);
|
String error = NBCLIErrorHandler.handle(e, showStackTraces);
|
||||||
// Commented for now, as the above handler should do everything needed.
|
// Commented for now, as the above handler should do everything needed.
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
System.err.println("Scenario stopped due to error. See logs for details.");
|
System.err.println("Scenario stopped due to error. See logs for details.");
|
||||||
@ -150,7 +154,7 @@ public class NBCLI implements Function<String[], Integer> {
|
|||||||
.setConsolePattern(globalOptions.getConsoleLoggingPattern())
|
.setConsolePattern(globalOptions.getConsoleLoggingPattern())
|
||||||
.setLogfileLevel(globalOptions.getScenarioLogLevel())
|
.setLogfileLevel(globalOptions.getScenarioLogLevel())
|
||||||
.setLogfilePattern(globalOptions.getLogfileLoggingPattern())
|
.setLogfilePattern(globalOptions.getLogfileLoggingPattern())
|
||||||
.getLoggerLevelOverrides(globalOptions.getLogLevelOverrides())
|
.setLoggerLevelOverrides(globalOptions.getLogLevelOverrides())
|
||||||
.setMaxLogs(globalOptions.getLogsMax())
|
.setMaxLogs(globalOptions.getLogsMax())
|
||||||
.setLogsDirectory(globalOptions.getLogsDirectory())
|
.setLogsDirectory(globalOptions.getLogsDirectory())
|
||||||
.setAnsiEnabled(globalOptions.isEnableAnsi())
|
.setAnsiEnabled(globalOptions.isEnableAnsi())
|
||||||
@ -175,10 +179,10 @@ public class NBCLI implements Function<String[], Integer> {
|
|||||||
|
|
||||||
// Invoke any bundled app which matches the name of the first non-option argument, if it exists.
|
// Invoke any bundled app which matches the name of the first non-option argument, if it exists.
|
||||||
// If it does not, continue with no fanfare. Let it drop through to other command resolution methods.
|
// If it does not, continue with no fanfare. Let it drop through to other command resolution methods.
|
||||||
if (args.length>0 && args[0].matches("\\w[\\w\\d-_.]+")) {
|
if (args.length > 0 && args[0].matches("\\w[\\w\\d-_.]+")) {
|
||||||
ServiceSelector<BundledApp> apploader = ServiceSelector.of(args[0], ServiceLoader.load(BundledApp.class));
|
ServiceSelector<BundledApp> apploader = ServiceSelector.of(args[0], ServiceLoader.load(BundledApp.class));
|
||||||
BundledApp app = apploader.get().orElse(null);
|
BundledApp app = apploader.get().orElse(null);
|
||||||
if (app!=null) {
|
if (app != null) {
|
||||||
String[] appargs = Arrays.copyOfRange(args, 1, args.length);
|
String[] appargs = Arrays.copyOfRange(args, 1, args.length);
|
||||||
logger.info("invoking bundled app '" + args[0] + "' (" + app.getClass().getSimpleName() + ").");
|
logger.info("invoking bundled app '" + args[0] + "' (" + app.getClass().getSimpleName() + ").");
|
||||||
globalOptions.setWantsStackTraces(true);
|
globalOptions.setWantsStackTraces(true);
|
||||||
@ -211,10 +215,10 @@ public class NBCLI implements Function<String[], Integer> {
|
|||||||
DockerMetricsManager.GRAFANA_TAG, globalOptions.getDockerGrafanaTag(),
|
DockerMetricsManager.GRAFANA_TAG, globalOptions.getDockerGrafanaTag(),
|
||||||
DockerMetricsManager.PROM_TAG, globalOptions.getDockerPromTag(),
|
DockerMetricsManager.PROM_TAG, globalOptions.getDockerPromTag(),
|
||||||
DockerMetricsManager.TSDB_RETENTION, String.valueOf(globalOptions.getDockerPromRetentionDays()),
|
DockerMetricsManager.TSDB_RETENTION, String.valueOf(globalOptions.getDockerPromRetentionDays()),
|
||||||
DockerMetricsManager.GRAPHITE_SAMPLE_EXPIRY,"10m",
|
DockerMetricsManager.GRAPHITE_SAMPLE_EXPIRY, "10m",
|
||||||
DockerMetricsManager.GRAPHITE_CACHE_SIZE,"5000",
|
DockerMetricsManager.GRAPHITE_CACHE_SIZE, "5000",
|
||||||
DockerMetricsManager.GRAPHITE_LOG_LEVEL,globalOptions.getGraphiteLogLevel(),
|
DockerMetricsManager.GRAPHITE_LOG_LEVEL, globalOptions.getGraphiteLogLevel(),
|
||||||
DockerMetricsManager.GRAPHITE_LOG_FORMAT,"logfmt"
|
DockerMetricsManager.GRAPHITE_LOG_FORMAT, "logfmt"
|
||||||
|
|
||||||
);
|
);
|
||||||
dmh.startMetrics(dashboardOptions);
|
dmh.startMetrics(dashboardOptions);
|
||||||
@ -262,7 +266,7 @@ public class NBCLI implements Function<String[], Integer> {
|
|||||||
for (ServiceLoader.Provider<BundledApp> provider : loader.stream().toList()) {
|
for (ServiceLoader.Provider<BundledApp> provider : loader.stream().toList()) {
|
||||||
Class<? extends BundledApp> appType = provider.type();
|
Class<? extends BundledApp> appType = provider.type();
|
||||||
String name = appType.getAnnotation(Service.class).selector();
|
String name = appType.getAnnotation(Service.class).selector();
|
||||||
System.out.println(String.format("%-40s %s",name,appType.getCanonicalName()));
|
System.out.printf("%-40s %s%n", name, appType.getCanonicalName());
|
||||||
}
|
}
|
||||||
return EXIT_OK;
|
return EXIT_OK;
|
||||||
}
|
}
|
||||||
@ -316,25 +320,25 @@ public class NBCLI implements Function<String[], Integer> {
|
|||||||
|
|
||||||
Path writeTo = Path.of(data.asPath().getFileName().toString());
|
Path writeTo = Path.of(data.asPath().getFileName().toString());
|
||||||
if (Files.exists(writeTo)) {
|
if (Files.exists(writeTo)) {
|
||||||
throw new BasicError("A file named " + writeTo.toString() + " exists. Remove it first.");
|
throw new BasicError("A file named " + writeTo + " exists. Remove it first.");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Files.writeString(writeTo, data.getCharBuffer(), StandardCharsets.UTF_8);
|
Files.writeString(writeTo, data.getCharBuffer(), StandardCharsets.UTF_8);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new BasicError("Unable to write to " + writeTo.toString() + ": " + e.getMessage());
|
throw new BasicError("Unable to write to " + writeTo + ": " + e.getMessage());
|
||||||
}
|
}
|
||||||
logger.info("Copied internal resource '" + data.asPath() + "' to '" + writeTo.toString() + "'");
|
logger.info("Copied internal resource '" + data.asPath() + "' to '" + writeTo + "'");
|
||||||
return EXIT_OK;
|
return EXIT_OK;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.wantsInputTypes()) {
|
if (options.wantsInputTypes()) {
|
||||||
InputType.FINDER.getAllSelectors().forEach((k,v) -> System.out.println(k + " (" + v.name() + ")"));
|
InputType.FINDER.getAllSelectors().forEach((k, v) -> System.out.println(k + " (" + v.name() + ")"));
|
||||||
return EXIT_OK;
|
return EXIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.wantsMarkerTypes()) {
|
if (options.wantsMarkerTypes()) {
|
||||||
OutputType.FINDER.getAllSelectors().forEach((k,v) -> System.out.println(k + " (" + v.name() + ")"));
|
OutputType.FINDER.getAllSelectors().forEach((k, v) -> System.out.println(k + " (" + v.name() + ")"));
|
||||||
return EXIT_OK;
|
return EXIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,27 +468,27 @@ public class NBCLI implements Function<String[], Integer> {
|
|||||||
|
|
||||||
executor.execute(scenario);
|
executor.execute(scenario);
|
||||||
|
|
||||||
while (true) {
|
// while (true) {
|
||||||
Optional<ScenarioResult> pendingResult = executor.getPendingResult(scenario.getScenarioName());
|
// Optional<ScenarioResult> pendingResult = executor.getPendingResult(scenario.getScenarioName());
|
||||||
if (pendingResult.isEmpty()) {
|
// if (pendingResult.isPresent()) {
|
||||||
LockSupport.parkNanos(100000000L);
|
// break;
|
||||||
} else {
|
// }
|
||||||
break;
|
// LockSupport.parkNanos(100000000L);
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
ScenariosResults scenariosResults = executor.awaitAllResults();
|
ScenariosResults scenariosResults = executor.awaitAllResults();
|
||||||
|
logger.debug("Total of " + scenariosResults.getSize() + " result object returned from ScenariosExecutor");
|
||||||
|
|
||||||
ActivityMetrics.closeMetrics(options.wantsEnableChart());
|
ActivityMetrics.closeMetrics(options.wantsEnableChart());
|
||||||
//scenariosResults.reportToLog();
|
scenariosResults.reportToLog();
|
||||||
ShutdownManager.shutdown();
|
ShutdownManager.shutdown();
|
||||||
|
|
||||||
// logger.info(scenariosResults.getExecutionSummary());
|
logger.info(scenariosResults.getExecutionSummary());
|
||||||
|
|
||||||
if (scenariosResults.hasError()) {
|
if (scenariosResults.hasError()) {
|
||||||
Exception exception = scenariosResults.getOne().getException().get();
|
Exception exception = scenariosResults.getOne().getException().get();
|
||||||
// logger.warn(scenariosResults.getExecutionSummary());
|
logger.warn(scenariosResults.getExecutionSummary());
|
||||||
ScenarioErrorHandler.handle(exception, options.wantsStackTraces());
|
NBCLIErrorHandler.handle(exception, options.wantsStackTraces());
|
||||||
System.err.println(exception.getMessage()); // TODO: make this consistent with ConsoleLogging sequencing
|
System.err.println(exception.getMessage()); // TODO: make this consistent with ConsoleLogging sequencing
|
||||||
return EXIT_ERROR;
|
return EXIT_ERROR;
|
||||||
} else {
|
} else {
|
||||||
|
@ -16,16 +16,24 @@
|
|||||||
|
|
||||||
package io.nosqlbench.engine.core.lifecycle;
|
package io.nosqlbench.engine.core.lifecycle;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
public class ActivityExceptionHandler implements Thread.UncaughtExceptionHandler {
|
public class ActivityExceptionHandler implements Thread.UncaughtExceptionHandler {
|
||||||
|
|
||||||
|
private static final Logger logger = LogManager.getLogger(ActivityExceptionHandler.class);
|
||||||
|
|
||||||
private final ActivityExecutor executor;
|
private final ActivityExecutor executor;
|
||||||
|
|
||||||
public ActivityExceptionHandler(ActivityExecutor executor) {
|
public ActivityExceptionHandler(ActivityExecutor executor) {
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
|
logger.debug(() -> "Activity exception handler starting up for executor '" + executor + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void uncaughtException(Thread t, Throwable e) {
|
public void uncaughtException(Thread t, Throwable e) {
|
||||||
|
logger.error("Uncaught exception in thread '" + t.getName() + ", state[" + t.getState() + "], notifying executor '" + executor + "'");
|
||||||
executor.notifyException(t, e);
|
executor.notifyException(t, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,14 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package io.nosqlbench.engine.core.lifecycle;
|
package io.nosqlbench.engine.core.lifecycle;
|
||||||
|
|
||||||
|
import io.nosqlbench.api.annotations.Annotation;
|
||||||
|
import io.nosqlbench.api.annotations.Layer;
|
||||||
|
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
|
||||||
|
import io.nosqlbench.api.engine.activityimpl.ParameterMap;
|
||||||
import io.nosqlbench.engine.api.activityapi.core.*;
|
import io.nosqlbench.engine.api.activityapi.core.*;
|
||||||
import io.nosqlbench.engine.api.activityapi.core.progress.ProgressCapable;
|
import io.nosqlbench.engine.api.activityapi.core.progress.ProgressCapable;
|
||||||
import io.nosqlbench.engine.api.activityapi.core.progress.ProgressMeterDisplay;
|
import io.nosqlbench.engine.api.activityapi.core.progress.ProgressMeterDisplay;
|
||||||
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
|
|
||||||
import io.nosqlbench.api.engine.activityimpl.ParameterMap;
|
|
||||||
import io.nosqlbench.engine.core.annotation.Annotators;
|
import io.nosqlbench.engine.core.annotation.Annotators;
|
||||||
import io.nosqlbench.api.annotations.Annotation;
|
|
||||||
import io.nosqlbench.api.annotations.Layer;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
@ -155,8 +155,8 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized RuntimeException forceStopScenario(int initialMillisToWait) {
|
public synchronized RuntimeException forceStopScenario(int initialMillisToWait) {
|
||||||
activitylogger.debug("FORCE STOP/before alias=(" + activity.getAlias() + ")");
|
|
||||||
|
|
||||||
|
activitylogger.debug("FORCE STOP/before alias=(" + activity.getAlias() + ")");
|
||||||
activity.setRunState(RunState.Stopped);
|
activity.setRunState(RunState.Stopped);
|
||||||
|
|
||||||
executorService.shutdown();
|
executorService.shutdown();
|
||||||
@ -214,23 +214,29 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean finishAndShutdownExecutor(int secondsToWait) {
|
public boolean finishAndShutdownExecutor(int secondsToWait) {
|
||||||
activitylogger.debug("REQUEST STOP/before alias=(" + activity.getAlias() + ")");
|
|
||||||
|
|
||||||
|
activitylogger.debug("REQUEST STOP/before alias=(" + activity.getAlias() + ")");
|
||||||
logger.debug("Stopping executor for " + activity.getAlias() + " when work completes.");
|
logger.debug("Stopping executor for " + activity.getAlias() + " when work completes.");
|
||||||
|
|
||||||
executorService.shutdown();
|
|
||||||
boolean wasStopped = false;
|
boolean wasStopped = false;
|
||||||
try {
|
try {
|
||||||
|
executorService.shutdown();
|
||||||
logger.trace(() -> "awaiting termination with timeout of " + secondsToWait + " seconds");
|
logger.trace(() -> "awaiting termination with timeout of " + secondsToWait + " seconds");
|
||||||
wasStopped = executorService.awaitTermination(secondsToWait, TimeUnit.SECONDS);
|
wasStopped = executorService.awaitTermination(secondsToWait, TimeUnit.SECONDS);
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
logger.trace("interrupted while awaiting termination");
|
logger.trace("interrupted while awaiting termination");
|
||||||
wasStopped = false;
|
wasStopped = false;
|
||||||
logger.warn("while waiting termination of activity " + activity.getAlias() + ", " + ie.getMessage());
|
logger.warn("while waiting termination of shutdown " + activity.getAlias() + ", " + ie.getMessage());
|
||||||
activitylogger.debug("REQUEST STOP/exception alias=(" + activity.getAlias() + ") wasstopped=" + wasStopped);
|
activitylogger.debug("REQUEST STOP/exception alias=(" + activity.getAlias() + ") wasstopped=" + wasStopped);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
logger.trace("Received exception while awaiting termination: " + e.getMessage());
|
||||||
|
wasStopped = true;
|
||||||
|
stoppingException = e;
|
||||||
} finally {
|
} finally {
|
||||||
|
|
||||||
logger.trace(() -> "finally shutting down activity " + this.getActivity().getAlias());
|
logger.trace(() -> "finally shutting down activity " + this.getActivity().getAlias());
|
||||||
activity.shutdownActivity();
|
activity.shutdownActivity();
|
||||||
|
|
||||||
logger.trace("closing auto-closeables");
|
logger.trace("closing auto-closeables");
|
||||||
activity.closeAutoCloseables();
|
activity.closeAutoCloseables();
|
||||||
activity.setRunState(RunState.Stopped);
|
activity.setRunState(RunState.Stopped);
|
||||||
@ -241,6 +247,7 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
|
|||||||
logger.trace(() -> "an exception caused the activity to stop:" + stoppingException.getMessage());
|
logger.trace(() -> "an exception caused the activity to stop:" + stoppingException.getMessage());
|
||||||
throw stoppingException;
|
throw stoppingException;
|
||||||
}
|
}
|
||||||
|
|
||||||
activitylogger.debug("REQUEST STOP/after alias=(" + activity.getAlias() + ") wasstopped=" + wasStopped);
|
activitylogger.debug("REQUEST STOP/after alias=(" + activity.getAlias() + ") wasstopped=" + wasStopped);
|
||||||
|
|
||||||
return wasStopped;
|
return wasStopped;
|
||||||
@ -278,11 +285,13 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
|
|||||||
* This is the canonical way to wait for an activity to finish. It ties together
|
* This is the canonical way to wait for an activity to finish. It ties together
|
||||||
* any way that an activity can finish under one blocking call.
|
* any way that an activity can finish under one blocking call.
|
||||||
* This should be awaited asynchronously from the control layer in separate threads.
|
* This should be awaited asynchronously from the control layer in separate threads.
|
||||||
*
|
* <p>
|
||||||
* TODO: move activity finisher threaad to this class and remove separate implementation
|
* TODO: move activity finisher thread to this class and remove separate implementation
|
||||||
*/
|
*/
|
||||||
public boolean awaitCompletion(int waitTime) {
|
public boolean awaitCompletion(int waitTime) {
|
||||||
|
logger.debug(()-> "awaiting completion of '" + this.getActivity().getAlias() + "'");
|
||||||
boolean finished = finishAndShutdownExecutor(waitTime);
|
boolean finished = finishAndShutdownExecutor(waitTime);
|
||||||
|
|
||||||
Annotators.recordAnnotation(Annotation.newBuilder()
|
Annotators.recordAnnotation(Annotation.newBuilder()
|
||||||
.session(sessionId)
|
.session(sessionId)
|
||||||
.interval(startedAt, this.stoppedAt)
|
.interval(startedAt, this.stoppedAt)
|
||||||
@ -412,7 +421,7 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
|
|||||||
* Await a thread (aka motor/slot) entering a specific SlotState
|
* Await a thread (aka motor/slot) entering a specific SlotState
|
||||||
*
|
*
|
||||||
* @param m motor instance
|
* @param m motor instance
|
||||||
* @param waitTime milliseconds to wait, total
|
* @param waitTime milliseco`nds to wait, total
|
||||||
* @param pollTime polling interval between state checks
|
* @param pollTime polling interval between state checks
|
||||||
* @param desiredRunStates any desired SlotState
|
* @param desiredRunStates any desired SlotState
|
||||||
* @return true, if the desired SlotState was detected
|
* @return true, if the desired SlotState was detected
|
||||||
@ -521,7 +530,7 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void notifyException(Thread t, Throwable e) {
|
public synchronized void notifyException(Thread t, Throwable e) {
|
||||||
//logger.error("Uncaught exception in activity thread forwarded to activity executor:", e);
|
logger.debug(() -> "Uncaught exception in activity thread forwarded to activity executor: " + e.getMessage());
|
||||||
this.stoppingException = new RuntimeException("Error in activity thread " + t.getName(), e);
|
this.stoppingException = new RuntimeException("Error in activity thread " + t.getName(), e);
|
||||||
forceStopScenario(10000);
|
forceStopScenario(10000);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,11 @@
|
|||||||
|
|
||||||
package io.nosqlbench.engine.core.lifecycle;
|
package io.nosqlbench.engine.core.lifecycle;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
public class ActivityFinisher extends Thread {
|
public class ActivityFinisher extends Thread {
|
||||||
|
private final static Logger logger = LogManager.getLogger(ActivityFinisher.class);
|
||||||
|
|
||||||
private final ActivityExecutor executor;
|
private final ActivityExecutor executor;
|
||||||
private final int timeout;
|
private final int timeout;
|
||||||
@ -30,10 +34,17 @@ public class ActivityFinisher extends Thread {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
logger.debug(this + " awaiting async completion of " + executor.getActivity().getAlias() + " on " + executor + " for timeout " + timeout);
|
||||||
result = executor.awaitCompletion(timeout);
|
result = executor.awaitCompletion(timeout);
|
||||||
|
logger.debug(this + " awaited async completion of " + executor.getActivity().getAlias());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getResult() {
|
public boolean getResult() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.getClass().getSimpleName()+"/" + executor.getActivity().getAlias();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
package io.nosqlbench.engine.core.lifecycle;
|
package io.nosqlbench.engine.core.lifecycle;
|
||||||
|
|
||||||
import io.nosqlbench.api.errors.BasicError;
|
import io.nosqlbench.api.errors.BasicError;
|
||||||
import org.graalvm.polyglot.PolyglotException;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.graalvm.polyglot.PolyglotException;
|
||||||
|
|
||||||
import javax.script.ScriptException;
|
import javax.script.ScriptException;
|
||||||
|
|
||||||
@ -32,28 +32,28 @@ import javax.script.ScriptException;
|
|||||||
* <ol>
|
* <ol>
|
||||||
* <li>Report an error in the most intelligible way to the user.</li>
|
* <li>Report an error in the most intelligible way to the user.</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
*
|
* <p>
|
||||||
* That is all. When this error handler is invoked, it is a foregone conclusion that the scenario
|
* That is all. When this error handler is invoked, it is a foregone conclusion that the scenario
|
||||||
* is not able to continue, else the error would have been trapped and handled internal to a lower-level
|
* is not able to continue, else the error would have been trapped and handled internal to a lower-level
|
||||||
* class. It is the calling exception handler's responsibility to finally shut down the scenario
|
* class. It is the calling exception handler's responsibility to finally shut down the scenario
|
||||||
* cleanly and return appropriately. Thus, <em>You should not throw errors from this class. You should only
|
* cleanly and return appropriately. Thus, <em>You should not throw errors from this class. You should only
|
||||||
* unwrap and explain errors, sending contents to the logfile as appropriate.</em>
|
* unwrap and explain errors, sending contents to the logfile as appropriate.</em>
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class ScenarioErrorHandler {
|
public class NBCLIErrorHandler {
|
||||||
|
|
||||||
private final static Logger logger = LogManager.getLogger("ERRORHANDLER");
|
private final static Logger logger = LogManager.getLogger("ERRORHANDLER");
|
||||||
|
|
||||||
public static String handle(Throwable t, boolean wantsStackTraces) {
|
public static String handle(Throwable t, boolean wantsStackTraces) {
|
||||||
|
|
||||||
if (wantsStackTraces) {
|
if (wantsStackTraces) {
|
||||||
StackTraceElement[] st = Thread.currentThread().getStackTrace();
|
StackTraceElement[] st = Thread.currentThread().getStackTrace();
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
if (st.length>i) {
|
if (st.length > i) {
|
||||||
String className = st[i].getClassName();
|
String className = st[i].getClassName();
|
||||||
String fileName = st[i].getFileName();
|
String fileName = st[i].getFileName();
|
||||||
int lineNumber = st[i].getLineNumber();
|
int lineNumber = st[i].getLineNumber();
|
||||||
logger.trace("st["+i+"]:" + className +","+fileName+":"+lineNumber);
|
logger.trace("st[" + i + "]:" + className + "," + fileName + ":" + lineNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,18 +63,18 @@ public class ScenarioErrorHandler {
|
|||||||
} else if (t instanceof BasicError) {
|
} else if (t instanceof BasicError) {
|
||||||
logger.trace("Handling basic error: " + t);
|
logger.trace("Handling basic error: " + t);
|
||||||
return handleBasicError((BasicError) t, wantsStackTraces);
|
return handleBasicError((BasicError) t, wantsStackTraces);
|
||||||
} else if (t instanceof Exception){
|
} else if (t instanceof Exception) {
|
||||||
logger.trace("Handling general exception: " + t);
|
logger.trace("Handling general exception: " + t);
|
||||||
return handleInternalError((Exception) t, wantsStackTraces);
|
return handleInternalError((Exception) t, wantsStackTraces);
|
||||||
} else {
|
} else {
|
||||||
logger.error("Unknown type for error handler: " + t);
|
logger.error("Unknown type for error handler: " + t);
|
||||||
throw new RuntimeException("Error in exception handler", t);
|
throw new RuntimeException("Error in exception handler", t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String handleInternalError(Exception e, boolean wantsStackTraces) {
|
private static String handleInternalError(Exception e, boolean wantsStackTraces) {
|
||||||
String prefix = "internal error: ";
|
String prefix = "internal error: ";
|
||||||
if (e.getCause()!=null && !e.getCause().getClass().getCanonicalName().contains("io.nosqlbench")) {
|
if (e.getCause() != null && !e.getCause().getClass().getCanonicalName().contains("io.nosqlbench")) {
|
||||||
prefix = "Error from driver or included library: ";
|
prefix = "Error from driver or included library: ";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,13 +95,13 @@ public class ScenarioErrorHandler {
|
|||||||
if (cause instanceof PolyglotException) {
|
if (cause instanceof PolyglotException) {
|
||||||
Throwable hostException = ((PolyglotException) cause).asHostException();
|
Throwable hostException = ((PolyglotException) cause).asHostException();
|
||||||
if (hostException instanceof BasicError) {
|
if (hostException instanceof BasicError) {
|
||||||
handleBasicError((BasicError)hostException, wantsStackTraces);
|
handleBasicError((BasicError) hostException, wantsStackTraces);
|
||||||
} else {
|
} else {
|
||||||
handle(hostException, wantsStackTraces);
|
handle(hostException, wantsStackTraces);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (wantsStackTraces) {
|
if (wantsStackTraces) {
|
||||||
logger.error("Unknown script exception:",e);
|
logger.error("Unknown script exception:", e);
|
||||||
} else {
|
} else {
|
||||||
logger.error(e.getMessage());
|
logger.error(e.getMessage());
|
||||||
logger.error("for the full stack trace, run with --show-stacktraces");
|
logger.error("for the full stack trace, run with --show-stacktraces");
|
||||||
@ -112,7 +112,7 @@ public class ScenarioErrorHandler {
|
|||||||
|
|
||||||
private static String handleBasicError(BasicError e, boolean wantsStackTraces) {
|
private static String handleBasicError(BasicError e, boolean wantsStackTraces) {
|
||||||
if (wantsStackTraces) {
|
if (wantsStackTraces) {
|
||||||
logger.error(e.getMessage(),e);
|
logger.error(e.getMessage(), e);
|
||||||
} else {
|
} else {
|
||||||
logger.error(e.getMessage());
|
logger.error(e.getMessage());
|
||||||
logger.error("for the full stack trace, run with --show-stacktraces");
|
logger.error("for the full stack trace, run with --show-stacktraces");
|
@ -431,6 +431,7 @@ public class ScenarioController {
|
|||||||
* @return true, if all activities completed before the timer expired, false otherwise
|
* @return true, if all activities completed before the timer expired, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean awaitCompletion(long waitTimeMillis) {
|
public boolean awaitCompletion(long waitTimeMillis) {
|
||||||
|
logger.debug(() -> "awaiting completion");
|
||||||
boolean completed = true;
|
boolean completed = true;
|
||||||
long remaining = waitTimeMillis;
|
long remaining = waitTimeMillis;
|
||||||
|
|
||||||
@ -443,7 +444,9 @@ public class ScenarioController {
|
|||||||
|
|
||||||
for (ActivityFinisher finisher : finishers) {
|
for (ActivityFinisher finisher : finishers) {
|
||||||
try {
|
try {
|
||||||
|
logger.debug("joining finisher " + finisher.getName());
|
||||||
finisher.join(waitTimeMillis);
|
finisher.join(waitTimeMillis);
|
||||||
|
logger.debug("joined finisher " + finisher.getName());
|
||||||
} catch (InterruptedException ignored) {
|
} catch (InterruptedException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,17 +54,19 @@ public class ScenarioResult {
|
|||||||
private final long startedAt;
|
private final long startedAt;
|
||||||
private final long endedAt;
|
private final long endedAt;
|
||||||
|
|
||||||
private Exception exception;
|
private final Exception exception;
|
||||||
private final String iolog;
|
private final String iolog;
|
||||||
|
|
||||||
public ScenarioResult(String iolog, long startedAt, long endedAt) {
|
public ScenarioResult(Exception e, String iolog, long startedAt, long endedAt) {
|
||||||
this.iolog = iolog;
|
logger.debug("populating "+(e==null? "NORMAL" : "ERROR")+" scenario result");
|
||||||
this.startedAt = startedAt;
|
if (logger.isDebugEnabled()) {
|
||||||
this.endedAt = endedAt;
|
StackTraceElement[] st = Thread.currentThread().getStackTrace();
|
||||||
}
|
for (int i = 0; i < st.length; i++) {
|
||||||
|
logger.debug(":AT " + st[i].getFileName()+":"+st[i].getLineNumber()+":"+st[i].getMethodName());
|
||||||
public ScenarioResult(Exception e, long startedAt, long endedAt) {
|
if (i>10) break;
|
||||||
this.iolog = e.getMessage();
|
}
|
||||||
|
}
|
||||||
|
this.iolog = ((iolog!=null) ? iolog + "\n\n" : "") + (e!=null? e.getMessage() : "");
|
||||||
this.startedAt = startedAt;
|
this.startedAt = startedAt;
|
||||||
this.endedAt = endedAt;
|
this.endedAt = endedAt;
|
||||||
this.exception = e;
|
this.exception = e;
|
||||||
@ -147,15 +149,14 @@ public class ScenarioResult {
|
|||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
ActivityMetrics.getMetricRegistry().getMetrics().forEach((k, v) -> {
|
ActivityMetrics.getMetricRegistry().getMetrics().forEach((k, v) -> {
|
||||||
if (v instanceof Counting) {
|
if (v instanceof Counting counting) {
|
||||||
long count = ((Counting) v).getCount();
|
long count = counting.getCount();
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
NBMetricsSummary.summarize(sb, k, v);
|
NBMetricsSummary.summarize(sb, k, v);
|
||||||
}
|
}
|
||||||
} else if (v instanceof Gauge) {
|
} else if (v instanceof Gauge<?> gauge) {
|
||||||
Object value = ((Gauge) v).getValue();
|
Object value = gauge.getValue();
|
||||||
if (value != null && value instanceof Number) {
|
if (value instanceof Number n) {
|
||||||
Number n = (Number) value;
|
|
||||||
if (n.doubleValue() != 0) {
|
if (n.doubleValue() != 0) {
|
||||||
NBMetricsSummary.summarize(sb, k, v);
|
NBMetricsSummary.summarize(sb, k, v);
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ import java.util.Map;
|
|||||||
public class ScenariosResults {
|
public class ScenariosResults {
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger(ScenariosResults.class);
|
private static final Logger logger = LogManager.getLogger(ScenariosResults.class);
|
||||||
|
|
||||||
private final String scenariosExecutorName;
|
private final String scenariosExecutorName;
|
||||||
private final Map<Scenario, ScenarioResult> scenarioResultMap = new LinkedHashMap<>();
|
private final Map<Scenario, ScenarioResult> scenarioResultMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
@ -77,4 +76,8 @@ public class ScenariosResults {
|
|||||||
return this.scenarioResultMap.values().stream()
|
return this.scenarioResultMap.values().stream()
|
||||||
.anyMatch(r -> r.getException().isPresent());
|
.anyMatch(r -> r.getException().isPresent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return this.scenarioResultMap.size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,15 +29,14 @@ import org.apache.logging.log4j.core.config.ConfigurationSource;
|
|||||||
import org.apache.logging.log4j.core.config.builder.api.*;
|
import org.apache.logging.log4j.core.config.builder.api.*;
|
||||||
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
|
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
|
||||||
|
|
||||||
import java.nio.file.attribute.*;
|
|
||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.attribute.FileAttribute;
|
||||||
|
import java.nio.file.attribute.PosixFilePermission;
|
||||||
import java.nio.file.attribute.PosixFilePermissions;
|
import java.nio.file.attribute.PosixFilePermissions;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -55,10 +54,10 @@ import java.util.stream.Collectors;
|
|||||||
public class LoggerConfig extends ConfigurationFactory {
|
public class LoggerConfig extends ConfigurationFactory {
|
||||||
|
|
||||||
public static Map<String, String> STANDARD_FORMATS = Map.of(
|
public static Map<String, String> STANDARD_FORMATS = Map.of(
|
||||||
"TERSE", "%8r %-5level [%t] %-12logger{0} %msg%n%throwable",
|
"TERSE", "%8r %-5level [%t] %-12logger{0} %msg%n%throwable",
|
||||||
"VERBOSE", "%d{DEFAULT}{GMT} [%t] %logger %-5level: %msg%n%throwable",
|
"VERBOSE", "%d{DEFAULT}{GMT} [%t] %logger %-5level: %msg%n%throwable",
|
||||||
"TERSE-ANSI", "%8r %highlight{%-5level} %style{%C{1.} [%t] %-12logger{0}} %msg%n%throwable",
|
"TERSE-ANSI", "%8r %highlight{%-5level} %style{%C{1.} [%t] %-12logger{0}} %msg%n%throwable",
|
||||||
"VERBOSE-ANSI", "%d{DEFAULT}{GMT} [%t] %highlight{%logger %-5level}: %msg%n%throwable"
|
"VERBOSE-ANSI", "%d{DEFAULT}{GMT} [%t] %highlight{%logger %-5level}: %msg%n%throwable"
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,7 +65,7 @@ public class LoggerConfig extends ConfigurationFactory {
|
|||||||
* we squelch them to some reasonable level so they aren't a nuisance.
|
* we squelch them to some reasonable level so they aren't a nuisance.
|
||||||
*/
|
*/
|
||||||
public static Map<String, Level> BUILTIN_OVERRIDES = Map.of(
|
public static Map<String, Level> BUILTIN_OVERRIDES = Map.of(
|
||||||
"oshi.util", Level.INFO
|
"oshi.util", Level.INFO
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -151,20 +150,20 @@ public class LoggerConfig extends ConfigurationFactory {
|
|||||||
builder.setStatusLevel(internalLoggingStatusThreshold);
|
builder.setStatusLevel(internalLoggingStatusThreshold);
|
||||||
|
|
||||||
builder.add(
|
builder.add(
|
||||||
builder.newFilter(
|
builder.newFilter(
|
||||||
"ThresholdFilter",
|
"ThresholdFilter",
|
||||||
Filter.Result.ACCEPT,
|
Filter.Result.ACCEPT,
|
||||||
Filter.Result.NEUTRAL
|
Filter.Result.NEUTRAL
|
||||||
).addAttribute("level", builderThresholdLevel)
|
).addAttribute("level", builderThresholdLevel)
|
||||||
);
|
);
|
||||||
|
|
||||||
// CONSOLE appender
|
// CONSOLE appender
|
||||||
AppenderComponentBuilder appenderBuilder =
|
AppenderComponentBuilder appenderBuilder =
|
||||||
builder.newAppender("console", "CONSOLE")
|
builder.newAppender("console", "CONSOLE")
|
||||||
.addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
|
.addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
|
||||||
|
|
||||||
appenderBuilder.add(builder.newLayout("PatternLayout")
|
appenderBuilder.add(builder.newLayout("PatternLayout")
|
||||||
.addAttribute("pattern", consolePattern));
|
.addAttribute("pattern", consolePattern));
|
||||||
|
|
||||||
// appenderBuilder.add(
|
// appenderBuilder.add(
|
||||||
// builder.newFilter("MarkerFilter", Filter.Result.DENY, Filter.Result.NEUTRAL)
|
// builder.newFilter("MarkerFilter", Filter.Result.DENY, Filter.Result.NEUTRAL)
|
||||||
@ -174,8 +173,8 @@ public class LoggerConfig extends ConfigurationFactory {
|
|||||||
|
|
||||||
// Log4J internal logging
|
// Log4J internal logging
|
||||||
builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG)
|
builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG)
|
||||||
.add(builder.newAppenderRef("console"))
|
.add(builder.newAppenderRef("console"))
|
||||||
.addAttribute("additivity", false));
|
.addAttribute("additivity", false));
|
||||||
|
|
||||||
if (sessionName != null) {
|
if (sessionName != null) {
|
||||||
|
|
||||||
@ -189,55 +188,55 @@ public class LoggerConfig extends ConfigurationFactory {
|
|||||||
|
|
||||||
// LOGFILE appender
|
// LOGFILE appender
|
||||||
LayoutComponentBuilder logfileLayout = builder.newLayout("PatternLayout")
|
LayoutComponentBuilder logfileLayout = builder.newLayout("PatternLayout")
|
||||||
.addAttribute("pattern", logfilePattern);
|
.addAttribute("pattern", logfilePattern);
|
||||||
|
|
||||||
String filebase = getSessionName().replaceAll("\\s", "_");
|
String filebase = getSessionName().replaceAll("\\s", "_");
|
||||||
String logfilePath = loggerDir.resolve(filebase + ".log").toString();
|
String logfilePath = loggerDir.resolve(filebase + ".log").toString();
|
||||||
this.logfileLocation = logfilePath;
|
this.logfileLocation = logfilePath;
|
||||||
String archivePath = loggerDir.resolve(filebase + "-TIMESTAMP.log.gz").toString()
|
String archivePath = loggerDir.resolve(filebase + "-TIMESTAMP.log.gz").toString()
|
||||||
.replaceAll("TIMESTAMP", "%d{MM-dd-yy}");
|
.replaceAll("TIMESTAMP", "%d{MM-dd-yy}");
|
||||||
|
|
||||||
ComponentBuilder triggeringPolicy = builder.newComponent("Policies")
|
ComponentBuilder triggeringPolicy = builder.newComponent("Policies")
|
||||||
.addComponent(builder.newComponent("CronTriggeringPolicy").addAttribute("schedule", "0 0 0 * * ?"))
|
.addComponent(builder.newComponent("CronTriggeringPolicy").addAttribute("schedule", "0 0 0 * * ?"))
|
||||||
.addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", "100M"));
|
.addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", "100M"));
|
||||||
|
|
||||||
AppenderComponentBuilder logsAppenderBuilder =
|
AppenderComponentBuilder logsAppenderBuilder =
|
||||||
builder.newAppender("SCENARIO_APPENDER", RollingFileAppender.PLUGIN_NAME)
|
builder.newAppender("SCENARIO_APPENDER", RollingFileAppender.PLUGIN_NAME)
|
||||||
.addAttribute("fileName", logfilePath)
|
.addAttribute("fileName", logfilePath)
|
||||||
.addAttribute("filePattern", archivePath)
|
.addAttribute("filePattern", archivePath)
|
||||||
.addAttribute("append", false)
|
.addAttribute("append", false)
|
||||||
.add(logfileLayout)
|
.add(logfileLayout)
|
||||||
.addComponent(triggeringPolicy);
|
.addComponent(triggeringPolicy);
|
||||||
builder.add(logsAppenderBuilder);
|
builder.add(logsAppenderBuilder);
|
||||||
|
|
||||||
rootBuilder.add(
|
rootBuilder.add(
|
||||||
builder.newAppenderRef("SCENARIO_APPENDER")
|
builder.newAppenderRef("SCENARIO_APPENDER")
|
||||||
.addAttribute("level", fileLevel)
|
.addAttribute("level", fileLevel)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
rootBuilder.add(
|
rootBuilder.add(
|
||||||
builder.newAppenderRef("console")
|
builder.newAppenderRef("console")
|
||||||
.addAttribute("level",
|
.addAttribute("level",
|
||||||
consoleLevel
|
consoleLevel
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
builder.add(rootBuilder);
|
builder.add(rootBuilder);
|
||||||
|
|
||||||
BUILTIN_OVERRIDES.forEach((k, v) -> {
|
BUILTIN_OVERRIDES.forEach((k, v) -> {
|
||||||
builder.add(builder.newLogger(k, v)
|
builder.add(builder.newLogger(k, v)
|
||||||
.add(builder.newAppenderRef("console"))
|
.add(builder.newAppenderRef("console"))
|
||||||
.add(builder.newAppenderRef("SCENARIO_APPENDER"))
|
.add(builder.newAppenderRef("SCENARIO_APPENDER"))
|
||||||
.addAttribute("additivity", true));
|
.addAttribute("additivity", true));
|
||||||
});
|
});
|
||||||
|
|
||||||
logLevelOverrides.forEach((k, v) -> {
|
logLevelOverrides.forEach((k, v) -> {
|
||||||
Level olevel = Level.valueOf(v);
|
Level olevel = Level.valueOf(v);
|
||||||
builder.add(builder.newLogger(k, olevel)
|
builder.add(builder.newLogger(k, olevel)
|
||||||
.add(builder.newAppenderRef("console"))
|
.add(builder.newAppenderRef("console"))
|
||||||
.add(builder.newAppenderRef("SCENARIO_APPENDER"))
|
.add(builder.newAppenderRef("SCENARIO_APPENDER"))
|
||||||
.addAttribute("additivity", true));
|
.addAttribute("additivity", true));
|
||||||
});
|
});
|
||||||
|
|
||||||
BuiltConfiguration builtConfig = builder.build();
|
BuiltConfiguration builtConfig = builder.build();
|
||||||
@ -268,7 +267,7 @@ public class LoggerConfig extends ConfigurationFactory {
|
|||||||
if (!Files.exists(loggerDir)) {
|
if (!Files.exists(loggerDir)) {
|
||||||
try {
|
try {
|
||||||
FileAttribute<Set<PosixFilePermission>> attrs = PosixFilePermissions.asFileAttribute(
|
FileAttribute<Set<PosixFilePermission>> attrs = PosixFilePermissions.asFileAttribute(
|
||||||
PosixFilePermissions.fromString("rwxrwx---")
|
PosixFilePermissions.fromString("rwxrwx---")
|
||||||
);
|
);
|
||||||
Path directory = Files.createDirectory(loggerDir, attrs);
|
Path directory = Files.createDirectory(loggerDir, attrs);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -280,22 +279,22 @@ public class LoggerConfig extends ConfigurationFactory {
|
|||||||
|
|
||||||
public LoggerConfig setConsolePattern(String consoleLoggingPattern) {
|
public LoggerConfig setConsolePattern(String consoleLoggingPattern) {
|
||||||
|
|
||||||
consoleLoggingPattern= (ansiEnabled && STANDARD_FORMATS.containsKey(consoleLoggingPattern+"-ANSI"))
|
consoleLoggingPattern = (ansiEnabled && STANDARD_FORMATS.containsKey(consoleLoggingPattern + "-ANSI"))
|
||||||
? consoleLoggingPattern+"-ANSI" : consoleLoggingPattern;
|
? consoleLoggingPattern + "-ANSI" : consoleLoggingPattern;
|
||||||
|
|
||||||
this.consolePattern = STANDARD_FORMATS.getOrDefault(consoleLoggingPattern, consoleLoggingPattern);
|
this.consolePattern = STANDARD_FORMATS.getOrDefault(consoleLoggingPattern, consoleLoggingPattern);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoggerConfig setLogfilePattern(String logfileLoggingPattern) {
|
public LoggerConfig setLogfilePattern(String logfileLoggingPattern) {
|
||||||
logfileLoggingPattern= (logfileLoggingPattern.endsWith("-ANSI") && STANDARD_FORMATS.containsKey(logfileLoggingPattern))
|
logfileLoggingPattern = (logfileLoggingPattern.endsWith("-ANSI") && STANDARD_FORMATS.containsKey(logfileLoggingPattern))
|
||||||
? logfileLoggingPattern.substring(logfileLoggingPattern.length()-5) : logfileLoggingPattern;
|
? logfileLoggingPattern.substring(logfileLoggingPattern.length() - 5) : logfileLoggingPattern;
|
||||||
|
|
||||||
this.logfileLocation = STANDARD_FORMATS.getOrDefault(logfileLoggingPattern, logfileLoggingPattern);
|
this.logfileLocation = STANDARD_FORMATS.getOrDefault(logfileLoggingPattern, logfileLoggingPattern);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoggerConfig getLoggerLevelOverrides(Map<String, String> logLevelOverrides) {
|
public LoggerConfig setLoggerLevelOverrides(Map<String, String> logLevelOverrides) {
|
||||||
this.logLevelOverrides = logLevelOverrides;
|
this.logLevelOverrides = logLevelOverrides;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -334,9 +333,9 @@ public class LoggerConfig extends ConfigurationFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<File> toDelete = filesList.stream()
|
List<File> toDelete = filesList.stream()
|
||||||
.sorted(fileTimeComparator)
|
.sorted(fileTimeComparator)
|
||||||
.limit(remove)
|
.limit(remove)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
for (File file : toDelete) {
|
for (File file : toDelete) {
|
||||||
logger.info("removing extra logfile: " + file.getPath());
|
logger.info("removing extra logfile: " + file.getPath());
|
||||||
|
@ -17,8 +17,13 @@ package io.nosqlbench.engine.core.script;
|
|||||||
|
|
||||||
import com.codahale.metrics.MetricRegistry;
|
import com.codahale.metrics.MetricRegistry;
|
||||||
import com.oracle.truffle.js.scriptengine.GraalJSScriptEngine;
|
import com.oracle.truffle.js.scriptengine.GraalJSScriptEngine;
|
||||||
import io.nosqlbench.engine.api.extensions.ScriptingPluginInfo;
|
import io.nosqlbench.api.annotations.Annotation;
|
||||||
|
import io.nosqlbench.api.annotations.Layer;
|
||||||
import io.nosqlbench.api.engine.metrics.ActivityMetrics;
|
import io.nosqlbench.api.engine.metrics.ActivityMetrics;
|
||||||
|
import io.nosqlbench.api.metadata.ScenarioMetadata;
|
||||||
|
import io.nosqlbench.api.metadata.ScenarioMetadataAware;
|
||||||
|
import io.nosqlbench.api.metadata.SystemId;
|
||||||
|
import io.nosqlbench.engine.api.extensions.ScriptingPluginInfo;
|
||||||
import io.nosqlbench.engine.api.scripting.ScriptEnvBuffer;
|
import io.nosqlbench.engine.api.scripting.ScriptEnvBuffer;
|
||||||
import io.nosqlbench.engine.core.annotation.Annotators;
|
import io.nosqlbench.engine.core.annotation.Annotators;
|
||||||
import io.nosqlbench.engine.core.lifecycle.ActivityProgressIndicator;
|
import io.nosqlbench.engine.core.lifecycle.ActivityProgressIndicator;
|
||||||
@ -27,14 +32,12 @@ import io.nosqlbench.engine.core.lifecycle.ScenarioController;
|
|||||||
import io.nosqlbench.engine.core.lifecycle.ScenarioResult;
|
import io.nosqlbench.engine.core.lifecycle.ScenarioResult;
|
||||||
import io.nosqlbench.engine.core.metrics.PolyglotMetricRegistryBindings;
|
import io.nosqlbench.engine.core.metrics.PolyglotMetricRegistryBindings;
|
||||||
import io.nosqlbench.nb.annotations.Maturity;
|
import io.nosqlbench.nb.annotations.Maturity;
|
||||||
import io.nosqlbench.api.annotations.Annotation;
|
|
||||||
import io.nosqlbench.api.annotations.Layer;
|
|
||||||
import io.nosqlbench.api.metadata.ScenarioMetadata;
|
|
||||||
import io.nosqlbench.api.metadata.ScenarioMetadataAware;
|
|
||||||
import io.nosqlbench.api.metadata.SystemId;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.graalvm.polyglot.*;
|
import org.graalvm.polyglot.Context;
|
||||||
|
import org.graalvm.polyglot.EnvironmentAccess;
|
||||||
|
import org.graalvm.polyglot.HostAccess;
|
||||||
|
import org.graalvm.polyglot.PolyglotAccess;
|
||||||
|
|
||||||
import javax.script.Compilable;
|
import javax.script.Compilable;
|
||||||
import javax.script.CompiledScript;
|
import javax.script.CompiledScript;
|
||||||
@ -68,6 +71,12 @@ public class Scenario implements Callable<ScenarioResult> {
|
|||||||
private Exception error;
|
private Exception error;
|
||||||
private ScenarioMetadata scenarioMetadata;
|
private ScenarioMetadata scenarioMetadata;
|
||||||
|
|
||||||
|
private ScenarioResult result;
|
||||||
|
|
||||||
|
public Optional<ScenarioResult> getResultIfComplete() {
|
||||||
|
return Optional.ofNullable(this.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public enum State {
|
public enum State {
|
||||||
Scheduled,
|
Scheduled,
|
||||||
@ -162,10 +171,9 @@ public class Scenario implements Callable<ScenarioResult> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
private void initializeScriptingEngine() {
|
||||||
|
|
||||||
logger.debug("Using engine " + engine.toString());
|
logger.debug("Using engine " + engine.toString());
|
||||||
|
|
||||||
MetricRegistry metricRegistry = ActivityMetrics.getMetricRegistry();
|
MetricRegistry metricRegistry = ActivityMetrics.getMetricRegistry();
|
||||||
|
|
||||||
Context.Builder contextSettings = Context.newBuilder("js")
|
Context.Builder contextSettings = Context.newBuilder("js")
|
||||||
@ -183,7 +191,7 @@ public class Scenario implements Callable<ScenarioResult> {
|
|||||||
.option("js.nashorn-compat", "true");
|
.option("js.nashorn-compat", "true");
|
||||||
|
|
||||||
org.graalvm.polyglot.Engine.Builder engineBuilder = org.graalvm.polyglot.Engine.newBuilder();
|
org.graalvm.polyglot.Engine.Builder engineBuilder = org.graalvm.polyglot.Engine.newBuilder();
|
||||||
engineBuilder.option("engine.WarnInterpreterOnly","false");
|
engineBuilder.option("engine.WarnInterpreterOnly", "false");
|
||||||
org.graalvm.polyglot.Engine polyglotEngine = engineBuilder.build();
|
org.graalvm.polyglot.Engine polyglotEngine = engineBuilder.build();
|
||||||
|
|
||||||
// TODO: add in, out, err for this scenario
|
// TODO: add in, out, err for this scenario
|
||||||
@ -205,9 +213,9 @@ public class Scenario implements Callable<ScenarioResult> {
|
|||||||
// scriptEngine.put("metrics", new PolyglotMetricRegistryBindings(metricRegistry));
|
// scriptEngine.put("metrics", new PolyglotMetricRegistryBindings(metricRegistry));
|
||||||
// scriptEngine.put("activities", new NashornActivityBindings(scenarioController));
|
// scriptEngine.put("activities", new NashornActivityBindings(scenarioController));
|
||||||
|
|
||||||
scriptEngine.put("scenario", new PolyglotScenarioController(scenarioController));
|
scriptEngine.put("scenario", new PolyglotScenarioController(scenarioController));
|
||||||
scriptEngine.put("metrics", new PolyglotMetricRegistryBindings(metricRegistry));
|
scriptEngine.put("metrics", new PolyglotMetricRegistryBindings(metricRegistry));
|
||||||
scriptEngine.put("activities", new NashornActivityBindings(scenarioController));
|
scriptEngine.put("activities", new NashornActivityBindings(scenarioController));
|
||||||
|
|
||||||
for (ScriptingPluginInfo<?> extensionDescriptor : SandboxExtensionFinder.findAll()) {
|
for (ScriptingPluginInfo<?> extensionDescriptor : SandboxExtensionFinder.findAll()) {
|
||||||
if (!extensionDescriptor.isAutoLoading()) {
|
if (!extensionDescriptor.isAutoLoading()) {
|
||||||
@ -241,12 +249,11 @@ public class Scenario implements Callable<ScenarioResult> {
|
|||||||
return scenarioMetadata;
|
return scenarioMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void runScenario() {
|
private synchronized void runScenario() {
|
||||||
scenarioShutdownHook = new ScenarioShutdownHook(this);
|
scenarioShutdownHook = new ScenarioShutdownHook(this);
|
||||||
Runtime.getRuntime().addShutdownHook(scenarioShutdownHook);
|
Runtime.getRuntime().addShutdownHook(scenarioShutdownHook);
|
||||||
|
|
||||||
state = State.Running;
|
state = State.Running;
|
||||||
|
|
||||||
startedAtMillis = System.currentTimeMillis();
|
startedAtMillis = System.currentTimeMillis();
|
||||||
Annotators.recordAnnotation(
|
Annotators.recordAnnotation(
|
||||||
Annotation.newBuilder()
|
Annotation.newBuilder()
|
||||||
@ -256,21 +263,21 @@ public class Scenario implements Callable<ScenarioResult> {
|
|||||||
.detail("engine", this.engine.toString())
|
.detail("engine", this.engine.toString())
|
||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
init();
|
|
||||||
|
initializeScriptingEngine();
|
||||||
logger.debug("Running control script for " + getScenarioName() + ".");
|
logger.debug("Running control script for " + getScenarioName() + ".");
|
||||||
|
|
||||||
for (String script : scripts) {
|
for (String script : scripts) {
|
||||||
try {
|
try {
|
||||||
Object result = null;
|
Object result = null;
|
||||||
if (scriptEngine instanceof Compilable && wantsCompiledScript) {
|
if (scriptEngine instanceof Compilable compilableEngine && wantsCompiledScript) {
|
||||||
logger.debug("Using direct script compilation");
|
logger.debug("Using direct script compilation");
|
||||||
Compilable compilableEngine = (Compilable) scriptEngine;
|
|
||||||
CompiledScript compiled = compilableEngine.compile(script);
|
CompiledScript compiled = compilableEngine.compile(script);
|
||||||
logger.debug("-> invoking main scenario script (compiled)");
|
logger.debug("-> invoking main scenario script (compiled)");
|
||||||
result = compiled.eval();
|
result = compiled.eval();
|
||||||
logger.debug("<- scenario script completed (compiled)");
|
logger.debug("<- scenario script completed (compiled)");
|
||||||
} else {
|
} else {
|
||||||
if (scriptfile != null && !scriptfile.isEmpty()) {
|
if (scriptfile != null && !scriptfile.isEmpty()) {
|
||||||
|
|
||||||
String filename = scriptfile.replace("_SESSION_", scenarioName);
|
String filename = scriptfile.replace("_SESSION_", scenarioName);
|
||||||
logger.debug("-> invoking main scenario script (" +
|
logger.debug("-> invoking main scenario script (" +
|
||||||
"interpreted from " + filename + ")");
|
"interpreted from " + filename + ")");
|
||||||
@ -292,16 +299,21 @@ public class Scenario implements Callable<ScenarioResult> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
logger.debug("scenario result: type(" + result.getClass().getCanonicalName() + "): value:" + result.toString());
|
logger.debug("scenario result: type(" + result.getClass().getCanonicalName() + "): value:" + result);
|
||||||
}
|
}
|
||||||
System.err.flush();
|
System.err.flush();
|
||||||
System.out.flush();
|
System.out.flush();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
this.state = State.Errored;
|
this.state = State.Errored;
|
||||||
logger.error("Error in scenario, shutting down. (" + e.toString() + ")");
|
logger.error("Error in scenario, shutting down. (" + e + ")");
|
||||||
this.scenarioController.forceStopScenario(5000, false);
|
try {
|
||||||
this.error = e;
|
this.scenarioController.forceStopScenario(5000, false);
|
||||||
throw new RuntimeException(e);
|
} catch (Exception eInner) {
|
||||||
|
logger.debug("Found inner exception while forcing stop with rethrow=false: " + eInner);
|
||||||
|
} finally {
|
||||||
|
this.error = e;
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
System.out.flush();
|
System.out.flush();
|
||||||
System.err.flush();
|
System.err.flush();
|
||||||
@ -355,14 +367,29 @@ public class Scenario implements Callable<ScenarioResult> {
|
|||||||
return endedAtMillis;
|
return endedAtMillis;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScenarioResult call() {
|
/**
|
||||||
runScenario();
|
* This should be the only way to get a ScenarioResult for a Scenario.
|
||||||
String iolog = scriptEnv.getTimedLog();
|
*
|
||||||
ScenarioResult result = new ScenarioResult(iolog, this.startedAtMillis, this.endedAtMillis);
|
* @return
|
||||||
|
*/
|
||||||
|
public synchronized ScenarioResult call() {
|
||||||
|
if (result == null) {
|
||||||
|
try {
|
||||||
|
runScenario();
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (this.error!=null) {
|
||||||
|
logger.debug("OVERLAPPING ERRORS: prior" + this.error.getMessage() + ", current:" + e.getMessage());
|
||||||
|
}
|
||||||
|
this.error = e;
|
||||||
|
} finally {
|
||||||
|
logger.debug((this.error == null ? "NORMAL" : "ERRORED") + " scenario run");
|
||||||
|
}
|
||||||
|
|
||||||
result.reportToLog();
|
String iolog = scriptEnv.getTimedLog();
|
||||||
|
this.result = new ScenarioResult(this.error, iolog, this.startedAtMillis, this.endedAtMillis);
|
||||||
doReportSummaries(reportSummaryTo, result);
|
result.reportToLog();
|
||||||
|
doReportSummaries(reportSummaryTo, result);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,7 @@
|
|||||||
|
|
||||||
package io.nosqlbench.engine.core.script;
|
package io.nosqlbench.engine.core.script;
|
||||||
|
|
||||||
import io.nosqlbench.engine.core.lifecycle.IndexedThreadFactory;
|
import io.nosqlbench.engine.core.lifecycle.*;
|
||||||
import io.nosqlbench.engine.core.lifecycle.ScenarioController;
|
|
||||||
import io.nosqlbench.engine.core.lifecycle.ScenarioResult;
|
|
||||||
import io.nosqlbench.engine.core.lifecycle.ScenariosResults;
|
|
||||||
import io.nosqlbench.api.errors.BasicError;
|
import io.nosqlbench.api.errors.BasicError;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
@ -43,9 +40,9 @@ public class ScenariosExecutor {
|
|||||||
|
|
||||||
public ScenariosExecutor(String name, int threads) {
|
public ScenariosExecutor(String name, int threads) {
|
||||||
executor = new ThreadPoolExecutor(1, threads,
|
executor = new ThreadPoolExecutor(1, threads,
|
||||||
0L, TimeUnit.MILLISECONDS,
|
0L, TimeUnit.MILLISECONDS,
|
||||||
new LinkedBlockingQueue<>(),
|
new LinkedBlockingQueue<>(),
|
||||||
new IndexedThreadFactory("scenarios", new ScenarioExceptionHandler(this)));
|
new IndexedThreadFactory("scenarios", new ScenarioExceptionHandler(this)));
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +89,6 @@ public class ScenariosExecutor {
|
|||||||
long waitedAt = System.currentTimeMillis();
|
long waitedAt = System.currentTimeMillis();
|
||||||
long updateAt = Math.min(timeoutAt, waitedAt + updateInterval);
|
long updateAt = Math.min(timeoutAt, waitedAt + updateInterval);
|
||||||
while (!isShutdown && System.currentTimeMillis() < timeoutAt) {
|
while (!isShutdown && System.currentTimeMillis() < timeoutAt) {
|
||||||
|
|
||||||
while (!isShutdown && System.currentTimeMillis() < updateAt) {
|
while (!isShutdown && System.currentTimeMillis() < updateAt) {
|
||||||
try {
|
try {
|
||||||
long timeRemaining = updateAt - System.currentTimeMillis();
|
long timeRemaining = updateAt - System.currentTimeMillis();
|
||||||
@ -108,11 +104,17 @@ public class ScenariosExecutor {
|
|||||||
|
|
||||||
if (!isShutdown) {
|
if (!isShutdown) {
|
||||||
throw new RuntimeException("executor still runningScenarios after awaiting all results for " + timeout
|
throw new RuntimeException("executor still runningScenarios after awaiting all results for " + timeout
|
||||||
+ "ms. isTerminated:" + executor.isTerminated() + " isShutdown:" + executor.isShutdown());
|
+ "ms. isTerminated:" + executor.isTerminated() + " isShutdown:" + executor.isShutdown());
|
||||||
}
|
}
|
||||||
Map<Scenario, ScenarioResult> scenarioResultMap = new LinkedHashMap<>();
|
Map<Scenario, ScenarioResult> scenarioResultMap = new LinkedHashMap<>();
|
||||||
getAsyncResultStatus()
|
getAsyncResultStatus()
|
||||||
.entrySet().forEach(es -> scenarioResultMap.put(es.getKey(), es.getValue().orElse(null)));
|
.entrySet()
|
||||||
|
.forEach(
|
||||||
|
es -> scenarioResultMap.put(
|
||||||
|
es.getKey(),
|
||||||
|
es.getValue().orElse(null)
|
||||||
|
)
|
||||||
|
);
|
||||||
return new ScenariosResults(this, scenarioResultMap);
|
return new ScenariosResults(this, scenarioResultMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,9 +123,9 @@ public class ScenariosExecutor {
|
|||||||
*/
|
*/
|
||||||
public List<String> getPendingScenarios() {
|
public List<String> getPendingScenarios() {
|
||||||
return new ArrayList<>(
|
return new ArrayList<>(
|
||||||
submitted.values().stream()
|
submitted.values().stream()
|
||||||
.map(SubmittedScenario::getName)
|
.map(SubmittedScenario::getName)
|
||||||
.collect(Collectors.toCollection(ArrayList::new)));
|
.collect(Collectors.toCollection(ArrayList::new)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -149,7 +151,8 @@ public class ScenariosExecutor {
|
|||||||
oResult = Optional.of(resultFuture.get());
|
oResult = Optional.of(resultFuture.get());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
oResult = Optional.of(new ScenarioResult(e, now, now));
|
logger.debug("creating exceptional scenario result from getAsyncResultStatus");
|
||||||
|
oResult = Optional.of(new ScenarioResult(e, "errored output", now, now));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,23 +179,8 @@ public class ScenariosExecutor {
|
|||||||
* @param scenarioName the scenario name of interest
|
* @param scenarioName the scenario name of interest
|
||||||
* @return an optional result
|
* @return an optional result
|
||||||
*/
|
*/
|
||||||
public Optional<ScenarioResult> getPendingResult(String scenarioName) {
|
public Optional<Future<ScenarioResult>> getPendingResult(String scenarioName) {
|
||||||
|
return Optional.ofNullable(submitted.get(scenarioName)).map(s -> s.resultFuture);
|
||||||
Future<ScenarioResult> resultFuture1 = submitted.get(scenarioName).resultFuture;
|
|
||||||
if (resultFuture1 == null) {
|
|
||||||
throw new BasicError("Unknown scenario name:" + scenarioName);
|
|
||||||
}
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
if (resultFuture1.isDone()) {
|
|
||||||
try {
|
|
||||||
return Optional.ofNullable(resultFuture1.get());
|
|
||||||
} catch (Exception e) {
|
|
||||||
return Optional.of(new ScenarioResult(e, now, now));
|
|
||||||
}
|
|
||||||
} else if (resultFuture1.isCancelled()) {
|
|
||||||
return Optional.of(new ScenarioResult(new Exception("result was cancelled."), now, now));
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void stopScenario(String scenarioName) {
|
public synchronized void stopScenario(String scenarioName) {
|
||||||
@ -200,6 +188,7 @@ public class ScenariosExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void stopScenario(String scenarioName, boolean rethrow) {
|
public synchronized void stopScenario(String scenarioName, boolean rethrow) {
|
||||||
|
logger.debug("#stopScenario(name=" + scenarioName + ", rethrow="+ rethrow+")");
|
||||||
Optional<Scenario> pendingScenario = getPendingScenario(scenarioName);
|
Optional<Scenario> pendingScenario = getPendingScenario(scenarioName);
|
||||||
if (pendingScenario.isPresent()) {
|
if (pendingScenario.isPresent()) {
|
||||||
ScenarioController controller = pendingScenario.get().getScenarioController();
|
ScenarioController controller = pendingScenario.get().getScenarioController();
|
||||||
@ -256,6 +245,7 @@ public class ScenariosExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void notifyException(Thread t, Throwable e) {
|
public synchronized void notifyException(Thread t, Throwable e) {
|
||||||
|
logger.debug(() -> "Scenario executor uncaught exception: " + e.getMessage());
|
||||||
this.stoppingException = new RuntimeException("Error in scenario thread " + t.getName(), e);
|
this.stoppingException = new RuntimeException("Error in scenario thread " + t.getName(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,19 +19,27 @@ package io.nosqlbench.engine.core;
|
|||||||
import io.nosqlbench.engine.api.scripting.ScriptEnvBuffer;
|
import io.nosqlbench.engine.api.scripting.ScriptEnvBuffer;
|
||||||
import io.nosqlbench.engine.core.script.Scenario;
|
import io.nosqlbench.engine.core.script.Scenario;
|
||||||
import io.nosqlbench.nb.annotations.Maturity;
|
import io.nosqlbench.nb.annotations.Maturity;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
public class ScenarioTest {
|
public class ScenarioTest {
|
||||||
|
private final Logger logger = LogManager.getLogger(ScenarioTest.class);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldLoadScriptText() {
|
public void shouldLoadScriptText() {
|
||||||
ScriptEnvBuffer buffer = new ScriptEnvBuffer();
|
ScriptEnvBuffer buffer = new ScriptEnvBuffer();
|
||||||
Scenario env = new Scenario("testing", Scenario.Engine.Graalvm, "stdout:300", Maturity.Any);
|
Scenario scenario = new Scenario("testing", Scenario.Engine.Graalvm, "stdout:300", Maturity.Any);
|
||||||
env.addScriptText("print('loaded script environment...');\n");
|
scenario.addScriptText("print('loaded script environment...');\n");
|
||||||
env.runScenario();
|
try {
|
||||||
assertThat(env.getIOLog().get().get(0)).contains("loaded script environment...");
|
var result=scenario.call();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.debug("Scenario run encountered an exception: " + e.getMessage());
|
||||||
|
|
||||||
|
}
|
||||||
|
assertThat(scenario.getIOLog().get().get(0)).contains("loaded script environment...");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ import org.joda.time.format.DateTimeFormat;
|
|||||||
import java.io.CharArrayWriter;
|
import java.io.CharArrayWriter;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
@Service(value = WebServiceObject.class, selector = "scenario-executor")
|
@Service(value = WebServiceObject.class, selector = "scenario-executor")
|
||||||
@Singleton
|
@Singleton
|
||||||
@ -233,8 +234,9 @@ public class ScenarioExecutorEndpoint implements WebServiceObject {
|
|||||||
Optional<Scenario> pendingScenario = executor.getPendingScenario(scenarioName);
|
Optional<Scenario> pendingScenario = executor.getPendingScenario(scenarioName);
|
||||||
|
|
||||||
if (pendingScenario.isPresent()) {
|
if (pendingScenario.isPresent()) {
|
||||||
Optional<ScenarioResult> pendingResult = executor.getPendingResult(scenarioName);
|
Optional<Future<ScenarioResult>> pendingResult = executor.getPendingResult(scenarioName);
|
||||||
return new LiveScenarioView(pendingScenario.get(), pendingResult.orElse(null));
|
Future<ScenarioResult> scenarioResultFuture = pendingResult.get();
|
||||||
|
return new LiveScenarioView(pendingScenario.get());
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Scenario name '" + scenarioName + "' not found.");
|
throw new RuntimeException("Scenario name '" + scenarioName + "' not found.");
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ package io.nosqlbench.engine.rest.transfertypes;
|
|||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
|
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
|
||||||
import io.nosqlbench.engine.api.activityapi.core.progress.ProgressMeterDisplay;
|
import io.nosqlbench.engine.api.activityapi.core.progress.ProgressMeterDisplay;
|
||||||
import io.nosqlbench.engine.core.lifecycle.ScenarioResult;
|
|
||||||
import io.nosqlbench.engine.core.script.Scenario;
|
import io.nosqlbench.engine.core.script.Scenario;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -29,21 +28,16 @@ import java.util.List;
|
|||||||
public class LiveScenarioView {
|
public class LiveScenarioView {
|
||||||
|
|
||||||
private final Scenario scenario;
|
private final Scenario scenario;
|
||||||
private final ScenarioResult result;
|
|
||||||
|
|
||||||
public LiveScenarioView(Scenario scenario, ScenarioResult result) {
|
public LiveScenarioView(Scenario scenario) {
|
||||||
this.scenario = scenario;
|
this.scenario = scenario;
|
||||||
this.result = result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
@JsonPropertyDescription("Optionally populated result, "+
|
@JsonPropertyDescription("Optionally populated result, "+
|
||||||
" present only if there was an error or the scenario is complete")
|
" present only if there was an error or the scenario is complete")
|
||||||
public ResultView getResult() {
|
public ResultView getResult() {
|
||||||
if (result==null) {
|
return new ResultView(scenario.getResultIfComplete().orElse(null));
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new ResultView(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty("scenario_name")
|
@JsonProperty("scenario_name")
|
||||||
|
@ -27,14 +27,17 @@ public class ResultView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getIOLog() {
|
public String getIOLog() {
|
||||||
return result.getIOLog();
|
if (result!=null) {
|
||||||
}
|
return result.getIOLog();
|
||||||
|
|
||||||
public String getError() {
|
|
||||||
if (result.getException().isPresent()) {
|
|
||||||
return result.getException().get().getMessage();
|
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getError() {
|
||||||
|
if (result!=null && result.getException().isPresent()) {
|
||||||
|
return result.getException().get().getMessage();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,28 +57,28 @@ class ExitStatusIntegrationTests {
|
|||||||
assertThat(result.exitStatus).isEqualTo(2);
|
assertThat(result.exitStatus).isEqualTo(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temporarily disabled for triage
|
@Test
|
||||||
// TODO: figure out if github actions is an issue for this test.
|
void testExitStatusOnActivityBasicCommandException() {
|
||||||
// It passes locally, but fails spuriously in github actions runner
|
ProcessInvoker invoker = new ProcessInvoker();
|
||||||
// @Test
|
invoker.setLogDir("logs/test");
|
||||||
// public void testExitStatusOnActivityThreadException() {
|
|
||||||
// ProcessInvoker invoker = new ProcessInvoker();
|
// Forcing a thread exception via basic command issue.
|
||||||
// invoker.setLogDir("logs/test");
|
ProcessResult result = invoker.run("exitstatus_threadexception", 30,
|
||||||
// ProcessResult result = invoker.run("exitstatus_threadexception", 30,
|
"java", "-jar", JARNAME, "--logs-dir", "logs/test/threadexcep", "--logs-level", "debug", "run",
|
||||||
// "java", "-jar", JARNAME, "--logs-dir", "logs/test", "run", "driver=diag", "throwoncycle=10", "cycles=1000", "cyclerate=10", "-vvv"
|
"driver=diag", "cyclerate=10", "not_a_thing", "cycles=100", "-vvv"
|
||||||
// );
|
);
|
||||||
// String stdout = result.getStdoutData().stream().collect(Collectors.joining("\n"));
|
String stdout = String.join("\n", result.getStdoutData());
|
||||||
// assertThat(stdout).contains("Diag was asked to throw an error on cycle 10");
|
assertThat(stdout).contains("Could not recognize command");
|
||||||
// assertThat(result.exitStatus).isEqualTo(2);
|
assertThat(result.exitStatus).isEqualTo(2);
|
||||||
// }
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testExitStatusOnActivityOpException() {
|
void testExitStatusOnActivityOpException() {
|
||||||
ProcessInvoker invoker = new ProcessInvoker();
|
ProcessInvoker invoker = new ProcessInvoker();
|
||||||
invoker.setLogDir("logs/test");
|
invoker.setLogDir("logs/test");
|
||||||
ProcessResult result = invoker.run("exitstatus_asyncstoprequest", 30,
|
ProcessResult result = invoker.run("exitstatus_asyncstoprequest", 30,
|
||||||
java, "-jar", JARNAME, "--logs-dir", "logs/test/asyncstop", "run",
|
"java", "-jar", JARNAME, "--logs-dir", "logs/test/asyncstop", "--logs-level", "debug", "run",
|
||||||
"driver=diag", "cyclerate=1", "op=erroroncycle:erroroncycle=10", "cycles=2000", "-vvv"
|
"driver=diag", "threads=2", "cyclerate=10", "op=erroroncycle:erroroncycle=10", "cycles=500", "-vvv"
|
||||||
);
|
);
|
||||||
assertThat(result.exception).isNull();
|
assertThat(result.exception).isNull();
|
||||||
String stdout = String.join("\n", result.getStdoutData());
|
String stdout = String.join("\n", result.getStdoutData());
|
||||||
|
@ -16,10 +16,16 @@
|
|||||||
|
|
||||||
package io.nosqlbench.cli.testing;
|
package io.nosqlbench.cli.testing;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class ProcessInvoker {
|
public class ProcessInvoker {
|
||||||
|
|
||||||
|
private static final Logger logger = LogManager.getLogger(ProcessInvoker.class);
|
||||||
|
|
||||||
private File runDirectory = new File(".");
|
private File runDirectory = new File(".");
|
||||||
private File logDirectory = new File(".");
|
private File logDirectory = new File(".");
|
||||||
|
|
||||||
@ -49,13 +55,17 @@ public class ProcessInvoker {
|
|||||||
try {
|
try {
|
||||||
result.cmdDir = new File(".").getCanonicalPath();
|
result.cmdDir = new File(".").getCanonicalPath();
|
||||||
process = pb.start();
|
process = pb.start();
|
||||||
|
var handle = process.toHandle();
|
||||||
boolean terminated = process.waitFor(timeoutSeconds, TimeUnit.SECONDS);
|
boolean terminated = process.waitFor(timeoutSeconds, TimeUnit.SECONDS);
|
||||||
if (!terminated) {
|
if (!terminated) {
|
||||||
process.destroyForcibly().waitFor();
|
process.destroyForcibly().waitFor();
|
||||||
result.exception = new RuntimeException("timed out waiting for process, so it was shutdown forcibly.");
|
result.exception = new RuntimeException("timed out waiting for process, so it was shutdown forcibly.");
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
if (process != null) {
|
||||||
|
logger.debug("Exception received, with exit value: " + process.exitValue());
|
||||||
|
}
|
||||||
result.exception = e;
|
result.exception = e;
|
||||||
} finally {
|
} finally {
|
||||||
result.startNanosTime = startNanosTime;
|
result.startNanosTime = startNanosTime;
|
||||||
@ -66,7 +76,7 @@ public class ProcessInvoker {
|
|||||||
if (process != null) {
|
if (process != null) {
|
||||||
result.exitStatus = process.exitValue();
|
result.exitStatus = process.exitValue();
|
||||||
} else {
|
} else {
|
||||||
result.exitStatus=255;
|
result.exitStatus = 255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
Loading…
Reference in New Issue
Block a user