package org.radargun.stages.lifecycle;
import org.radargun.DistStageAck;
import org.radargun.config.Property;
import org.radargun.config.Stage;
import org.radargun.stages.AbstractDistStage;
import org.radargun.utils.TimeConverter;
/**
*
* Will simulate a node stop on specified nodes. If the used Service does not provide Killable trait
* it will always stop the node gracefully.
*
* @author Michal Linhard <mlinhard@redhat.com>
* @author Radim Vansa <rvansa@redhat.com>
*/
@Stage(doc = "Stops or kills (simulates node crash) one or more nodes.")
public class ServiceStopStage extends AbstractDistStage {
private static final String STOP_DELAY_THREAD = "_STOP_DELAY_THREAD_";
@Property(doc = "If set to false, the node crash should be simulated. By default node should be shutdown gracefully.")
private boolean graceful = true;
@Property(doc = "Timeout for the Lifecycle.stop() execution - if the stop() does not return within this timeout," +
" Killable.kill() is called (if it is supported). Default is 2 minutes.", converter = TimeConverter.class)
protected long gracefulStopTimeout = 120000;
@Property(doc = "If set to true the benchmark will not wait until the node is stopped. Default is false.")
private boolean async = false;
@Property(converter = TimeConverter.class, doc = "If this value is positive the stage will spawn a thread which " +
"will stop the node after the delay. The stage will not wait for anything. By default the stop is immediate " +
"and synchronous.")
private long delayExecution;
@Property(doc = "If set, the stage will not stop any node but will wait until the delayed execution is finished. " +
"Default is false.")
private boolean waitForDelayed = false;
public DistStageAck executeOnSlave() {
log.info("Received stop request from master...");
if (waitForDelayed) {
Thread t = (Thread) slaveState.get(STOP_DELAY_THREAD);
if (t != null) {
try {
t.join();
slaveState.remove(STOP_DELAY_THREAD);
} catch (InterruptedException e) {
return errorResponse("Interrupted while waiting for kill to be finished.", e);
}
} else {
log.info("No delayed execution found in history.");
}
} else if (shouldExecute()) {
if (delayExecution > 0) {
Thread t = new Thread() {
@Override
public void run() {
try {
Thread.sleep(delayExecution);
} catch (InterruptedException e) {
log.error("Thread has been interrupted", e);
Thread.currentThread().interrupt();
}
if (lifecycle == null || !lifecycle.isRunning()) {
log.info("The service on this node is not running or cannot be stopped");
} else {
LifecycleHelper.stop(slaveState, graceful, async, gracefulStopTimeout);
}
}
};
slaveState.put(STOP_DELAY_THREAD, t);
t.start();
} else {
if (lifecycle == null || !lifecycle.isRunning()) {
log.info("The service on this node is not running or cannot be stopped");
} else {
LifecycleHelper.stop(slaveState, graceful, async);
}
}
} else {
log.info("Ignoring stop request, not targeted for this slave");
}
return successfulResponse();
}
}