Browse Source

SONAR-12043 move hard stop timeout out of SQProcess#hardstop arguments

timeout is instead configured as state of SQProcess instance
this will allow calling hardStop with the right timeout from another method of SQProcess (the incoming stop() method)
tags/7.8
Sébastien Lesaint 5 years ago
parent
commit
16859cefcd

+ 5
- 2
server/sonar-main/src/main/java/org/sonar/application/SchedulerImpl.java View File

@@ -40,6 +40,8 @@ import org.sonar.application.process.ProcessMonitor;
import org.sonar.application.process.SQProcess;
import org.sonar.process.ProcessId;

import static org.sonar.application.process.SQProcess.Timeout.newTimeout;

public class SchedulerImpl implements Scheduler, ProcessEventListener, ProcessLifecycleListener, AppStateListener {

private static final Logger LOG = LoggerFactory.getLogger(SchedulerImpl.class);
@@ -89,6 +91,8 @@ public class SchedulerImpl implements Scheduler, ProcessEventListener, ProcessLi
.addProcessLifecycleListener(this)
.addEventListener(this)
.setWatcherDelayMs(processWatcherDelayMs)
// FIXME MMF-1673 timeout here must be changed to sonar.ce.task.timeout + 5 minutes if CE
.setHardStopTimeout(newTimeout(1, TimeUnit.MINUTES))
.build();
processesById.put(process.getProcessId(), process);
}
@@ -178,8 +182,7 @@ public class SchedulerImpl implements Scheduler, ProcessEventListener, ProcessLi
private void hardStopProcess(ProcessId processId) {
SQProcess process = processesById.get(processId);
if (process != null) {
// FIXME MMF-1673 timeout here must be changed to sonar.ce.task.timeout + 5 minutes if CE
process.hardStop(1, TimeUnit.MINUTES);
process.hardStop();
}
}


+ 52
- 4
server/sonar-main/src/main/java/org/sonar/application/process/SQProcess.java View File

@@ -21,6 +21,7 @@ package org.sonar.application.process;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
@@ -39,6 +40,7 @@ public class SQProcess {
private final ProcessId processId;
private final Lifecycle lifecycle;
private final List<ProcessEventListener> eventListeners;
private final Timeout hardStopTimeout;
private final long watcherDelayMs;

private ProcessMonitor process;
@@ -54,6 +56,7 @@ public class SQProcess {
this.processId = requireNonNull(builder.processId, "processId can't be null");
this.lifecycle = new Lifecycle(this.processId, builder.lifecycleListeners);
this.eventListeners = builder.eventListeners;
this.hardStopTimeout = builder.hardStopTimeout;
this.watcherDelayMs = builder.watcherDelayMs;
this.stopWatcher = new StopWatcher();
this.eventWatcher = new EventWatcher();
@@ -95,9 +98,9 @@ public class SQProcess {
* Sends kill signal and awaits termination. No guarantee that process is gracefully terminated (=shutdown hooks
* executed). It depends on OS.
*/
public void hardStop(long timeout, TimeUnit timeoutUnit) {
public void hardStop() {
if (lifecycle.tryToMoveTo(Lifecycle.State.HARD_STOPPING)) {
hardStopImpl(timeout, timeoutUnit);
hardStopImpl();
if (process != null && process.isAlive()) {
LOG.info("{} failed to stop in a quick fashion. Killing it.", processId.getKey());
}
@@ -120,13 +123,13 @@ public class SQProcess {
}
}

private void hardStopImpl(long timeout, TimeUnit timeoutUnit) {
private void hardStopImpl() {
if (process == null) {
return;
}
try {
process.askForHardStop();
process.waitFor(timeout, timeoutUnit);
process.waitFor(hardStopTimeout.getDuration(), hardStopTimeout.getUnit());
} catch (InterruptedException e) {
// can't wait for the termination of process. Let's assume it's down.
LOG.warn("Interrupted while hard stopping process {}", processId, e);
@@ -237,6 +240,7 @@ public class SQProcess {
private final List<ProcessEventListener> eventListeners = new ArrayList<>();
private final List<ProcessLifecycleListener> lifecycleListeners = new ArrayList<>();
private long watcherDelayMs = DEFAULT_WATCHER_DELAY_MS;
private Timeout hardStopTimeout = new Timeout(1, TimeUnit.MINUTES);

private Builder(ProcessId processId) {
this.processId = processId;
@@ -260,8 +264,52 @@ public class SQProcess {
return this;
}

public Builder setHardStopTimeout(Timeout hardStopTimeout) {
this.hardStopTimeout = requireNonNull(hardStopTimeout, "hardStopTimeout can't be null");
return this;
}

public SQProcess build() {
return new SQProcess(this);
}
}

public static final class Timeout {
private final long duration;
private final TimeUnit timeoutUnit;

private Timeout(long duration, TimeUnit unit) {
this.duration = duration;
this.timeoutUnit = Objects.requireNonNull(unit, "unit can't be null");
}

public static Timeout newTimeout(long duration, TimeUnit unit) {
return new Timeout(duration, unit);
}

public long getDuration() {
return duration;
}

public TimeUnit getUnit() {
return timeoutUnit;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Timeout timeout = (Timeout) o;
return duration == timeout.duration && timeoutUnit == timeout.timeoutUnit;
}

@Override
public int hashCode() {
return Objects.hash(duration, timeoutUnit);
}
}
}

+ 5
- 2
server/sonar-main/src/test/java/org/sonar/application/process/SQProcessTest.java View File

@@ -36,6 +36,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.sonar.application.process.SQProcess.Timeout.newTimeout;

public class SQProcessTest {

@@ -184,12 +185,13 @@ public class SQProcessTest {
ProcessLifecycleListener listener = mock(ProcessLifecycleListener.class);
SQProcess underTest = SQProcess.builder(A_PROCESS_ID)
.addProcessLifecycleListener(listener)
.setHardStopTimeout(newTimeout(1, TimeUnit.HOURS))
.build();

try (TestProcess testProcess = new TestProcess()) {
underTest.start(() -> testProcess);

Thread stopperThread = new Thread(() -> underTest.hardStop(1, TimeUnit.HOURS));
Thread stopperThread = new Thread(underTest::hardStop);
stopperThread.start();

// thread is blocked until process stopped
@@ -218,12 +220,13 @@ public class SQProcessTest {
ProcessLifecycleListener listener = mock(ProcessLifecycleListener.class);
SQProcess underTest = SQProcess.builder(A_PROCESS_ID)
.addProcessLifecycleListener(listener)
.setHardStopTimeout(newTimeout(1, TimeUnit.MILLISECONDS))
.build();

try (TestProcess testProcess = new TestProcess()) {
underTest.start(() -> testProcess);

underTest.hardStop(1L, TimeUnit.MILLISECONDS);
underTest.hardStop();

testProcess.waitFor();
assertThat(testProcess.askedForHardStop).isTrue();

Loading…
Cancel
Save