Skip to content

Commit

Permalink
Нативная реализация слежения за окончанием работы процесса
Browse files Browse the repository at this point in the history
Убран spring scheduler, error заменен на warn
  • Loading branch information
nixel2007 committed Sep 8, 2022
1 parent 770cf8b commit d7ac7e2
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@
import lombok.extern.slf4j.Slf4j;
import org.eclipse.lsp4j.services.LanguageServer;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.CheckForNull;
import java.util.Optional;

/**
* Наблюдатель за жизнью родительского процесса, запустившего Language Server.
*/
Expand All @@ -38,7 +40,6 @@
public class ParentProcessWatcher {

private final LanguageServer languageServer;
private long parentProcessId;

/**
* Обработчик события {@link LanguageServerInitializeRequestReceivedEvent}.
Expand All @@ -49,29 +50,23 @@ public class ParentProcessWatcher {
*/
@EventListener
public void handleEvent(LanguageServerInitializeRequestReceivedEvent event) {
var processId = event.getParams().getProcessId();
@CheckForNull Integer processId = event.getParams().getProcessId();
if (processId == null) {
return;
}
parentProcessId = processId;
}

/**
* Фоновая процедура, отслеживающая родительский процесс.
*/
@Scheduled(fixedDelay = 30000L)
public void watch() {
if (parentProcessId == 0) {
// Can't register onExit callback on current process.
if (ProcessHandle.current().pid() == processId) {
return;
}

boolean processIsAlive = ProcessHandle.of(parentProcessId)
.map(ProcessHandle::isAlive)
.orElse(false);

if (!processIsAlive) {
LOGGER.error("Parent process with pid {} is not found. Closing application...", parentProcessId);
languageServer.exit();
}
Optional.of(processId)
.flatMap(ProcessHandle::of)
.map(ProcessHandle::onExit)
.ifPresent(onExitCallback -> onExitCallback.thenRun(() -> {
LOGGER.warn("Parent process with pid {} is not found. Closing application...", processId);
languageServer.exit();
}));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,53 +25,63 @@
import org.eclipse.lsp4j.InitializeParams;
import org.eclipse.lsp4j.services.LanguageServer;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.time.Duration;

import static org.awaitility.Awaitility.await;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

@SpringBootTest
class ParentProcessWatcherTest {

@InjectMocks
private ParentProcessWatcher parentProcessWatcher;

@Mock
private LanguageServer languageServer;

@Test
void testParentProcessIsDead() {
void testParentProcessIsDead() throws IOException, InterruptedException {
// given
var languageServer = mock(LanguageServer.class);
var parentProcessWatcher = new ParentProcessWatcher(languageServer);

var params = new InitializeParams();
params.setProcessId(-1);
var process = new ProcessBuilder("timeout", "2").start();
var pid = process.pid();
params.setProcessId((int) pid);

var event = new LanguageServerInitializeRequestReceivedEvent(languageServer, params);
parentProcessWatcher.handleEvent(event);

// when
parentProcessWatcher.watch();
process.waitFor();

// then
verify(languageServer, times(1)).exit();
await()
.atMost(Duration.ofSeconds(1))
.untilAsserted(
() -> verify(languageServer, times(1)).exit()
);
}

@Test
void testParentProcessIsAlive() {
// given
var languageServer = mock(LanguageServer.class);
var parentProcessWatcher = new ParentProcessWatcher(languageServer);

var params = new InitializeParams();
params.setProcessId((int) ProcessHandle.current().pid());

var event = new LanguageServerInitializeRequestReceivedEvent(languageServer, params);
parentProcessWatcher.handleEvent(event);

// when
parentProcessWatcher.watch();
parentProcessWatcher.handleEvent(event);

// then
verify(languageServer, never()).exit();
await()
.atLeast(Duration.ofSeconds(1))
.untilAsserted(
() -> verify(languageServer, never()).exit()
);
}

}

0 comments on commit d7ac7e2

Please sign in to comment.