Implement build cancelation, fixes #127

This commit is contained in:
Guillaume Nodet
2020-11-09 12:56:18 +01:00
committed by Peter Palaga
parent 02ef4a2fc2
commit 0800aeb791
12 changed files with 168 additions and 78 deletions

View File

@@ -88,6 +88,10 @@ class ProjectExecutorService {
executor.shutdown();
}
public void cancel() {
executor.shutdownNow();
}
// hook to allow pausing executor during unit tests
protected void beforeExecute(Thread t, Runnable r) {
}

View File

@@ -70,16 +70,41 @@ public class SmartBuilder implements Builder {
private final LifecycleModuleBuilder moduleBuilder;
private volatile SmartBuilderImpl builder;
private volatile boolean canceled;
private static SmartBuilder INSTANCE;
public static SmartBuilder cancel() {
SmartBuilder builder = INSTANCE;
if (builder != null) {
builder.doCancel();
}
return builder;
}
@Inject
public SmartBuilder(LifecycleModuleBuilder moduleBuilder) {
this.moduleBuilder = moduleBuilder;
INSTANCE = this;
}
void doCancel() {
canceled = true;
SmartBuilderImpl b = builder;
if (b != null) {
b.cancel();
}
}
public void doneCancel() {
canceled = false;
}
@Override
public void build(final MavenSession session, final ReactorContext reactorContext,
public synchronized void build(final MavenSession session, final ReactorContext reactorContext,
ProjectBuildList projectBuilds, final List<TaskSegment> taskSegments,
ReactorBuildStatus reactorBuildStatus) throws ExecutionException, InterruptedException {
List<String> list = new ArrayList<>();
String providerScript = null;
@@ -165,9 +190,16 @@ public class SmartBuilder implements Builder {
List<Map.Entry<TaskSegment, ReactorBuildStats>> allstats = new ArrayList<>();
for (TaskSegment taskSegment : taskSegments) {
Set<MavenProject> projects = projectBuilds.getByTaskSegment(taskSegment).getProjects();
ReactorBuildStats stats = new SmartBuilderImpl(moduleBuilder, session, reactorContext, taskSegment, projects, graph)
.build();
allstats.add(new AbstractMap.SimpleEntry<>(taskSegment, stats));
if (canceled) {
return;
}
builder = new SmartBuilderImpl(moduleBuilder, session, reactorContext, taskSegment, projects, graph);
try {
ReactorBuildStats stats = builder.build();
allstats.add(new AbstractMap.SimpleEntry<>(taskSegment, stats));
} finally {
builder = null;
}
}
if (session.getResult().hasExceptions()) {

View File

@@ -157,6 +157,10 @@ class SmartBuilderImpl {
executor.shutdown();
}
public void cancel() {
executor.cancel();
}
private void submitAll(Set<MavenProject> readyProjects) {
List<ProjectBuildTask> tasks = new ArrayList<>();
for (MavenProject project : readyProjects) {

View File

@@ -41,6 +41,7 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.apache.maven.cli.DaemonMavenCli;
import org.apache.maven.execution.MavenSession;
import org.jboss.fuse.mvnd.builder.SmartBuilder;
import org.jboss.fuse.mvnd.common.DaemonConnection;
import org.jboss.fuse.mvnd.common.DaemonException;
import org.jboss.fuse.mvnd.common.DaemonExpirationStatus;
@@ -61,7 +62,9 @@ import org.jboss.fuse.mvnd.logging.smart.AbstractLoggingSpy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.jboss.fuse.mvnd.common.DaemonState.Broken;
import static org.jboss.fuse.mvnd.common.DaemonState.Busy;
import static org.jboss.fuse.mvnd.common.DaemonState.Canceled;
import static org.jboss.fuse.mvnd.common.DaemonState.StopRequested;
import static org.jboss.fuse.mvnd.common.DaemonState.Stopped;
@@ -267,7 +270,6 @@ public class Server implements AutoCloseable, Runnable {
condition.await();
break;
case Canceled:
LOGGER.debug("cancel requested.");
cancelNow();
break;
case Broken:
@@ -355,17 +357,12 @@ public class Server implements AutoCloseable, Runnable {
private void cancelNow() {
long time = System.currentTimeMillis() + CANCEL_TIMEOUT;
// LOGGER.debug("Cancel requested: will wait for daemon to become idle.");
// try {
// cancellationToken.cancel();
// } catch (Exception ex) {
// LOGGER.error("Cancel processing failed. Will continue.", ex);
// }
LOGGER.debug("Cancel requested: will wait for daemon to become idle.");
final SmartBuilder builder = SmartBuilder.cancel();
stateLock.lock();
try {
long rem;
while ((rem = System.currentTimeMillis() - time) > 0) {
while ((rem = time - System.currentTimeMillis()) > 0) {
try {
switch (getState()) {
case Idle:
@@ -391,6 +388,9 @@ public class Server implements AutoCloseable, Runnable {
stopNow("cancel requested but timed out");
} finally {
stateLock.unlock();
if (builder != null) {
builder.doneCancel();
}
}
}
@@ -447,12 +447,20 @@ public class Server implements AutoCloseable, Runnable {
break;
}
LOGGER.info("Received message: {}", message);
synchronized (recvQueue) {
recvQueue.put(message);
recvQueue.notifyAll();
if (message == Message.CANCEL_BUILD_SINGLETON) {
updateState(DaemonState.Canceled);
return;
} else {
synchronized (recvQueue) {
recvQueue.put(message);
recvQueue.notifyAll();
}
}
}
} catch (DaemonException.RecoverableMessageIOException t) {
updateState(Canceled);
} catch (Throwable t) {
updateState(Broken);
LOGGER.error("Error receiving events", t);
}
});

View File

@@ -19,6 +19,7 @@ import java.io.IOError;
import org.apache.maven.execution.MavenSession;
import org.jboss.fuse.mvnd.common.Message;
import org.jboss.fuse.mvnd.common.Message.BuildEvent;
import org.jboss.fuse.mvnd.common.Message.BuildStarted;
import org.jboss.fuse.mvnd.common.logging.TerminalOutput;
public class MavenLoggingSpy extends AbstractLoggingSpy {
@@ -32,7 +33,7 @@ public class MavenLoggingSpy extends AbstractLoggingSpy {
protected void onStartSession(MavenSession session) {
try {
output = new TerminalOutput(null);
output.accept(new Message.BuildStarted(
output.accept(new BuildStarted(
session.getTopLevelProject().getName(),
session.getAllProjects().size(),
session.getRequest().getDegreeOfConcurrency()));