Skip to content

Commit d7ac7e2

Browse files
committed
Нативная реализация слежения за окончанием работы процесса
Убран spring scheduler, error заменен на warn
1 parent 770cf8b commit d7ac7e2

File tree

2 files changed

+41
-36
lines changed

2 files changed

+41
-36
lines changed

src/main/java/com/github/_1c_syntax/bsl/languageserver/ParentProcessWatcher.java

+14-19
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626
import lombok.extern.slf4j.Slf4j;
2727
import org.eclipse.lsp4j.services.LanguageServer;
2828
import org.springframework.context.event.EventListener;
29-
import org.springframework.scheduling.annotation.Scheduled;
3029
import org.springframework.stereotype.Component;
3130

31+
import javax.annotation.CheckForNull;
32+
import java.util.Optional;
33+
3234
/**
3335
* Наблюдатель за жизнью родительского процесса, запустившего Language Server.
3436
*/
@@ -38,7 +40,6 @@
3840
public class ParentProcessWatcher {
3941

4042
private final LanguageServer languageServer;
41-
private long parentProcessId;
4243

4344
/**
4445
* Обработчик события {@link LanguageServerInitializeRequestReceivedEvent}.
@@ -49,29 +50,23 @@ public class ParentProcessWatcher {
4950
*/
5051
@EventListener
5152
public void handleEvent(LanguageServerInitializeRequestReceivedEvent event) {
52-
var processId = event.getParams().getProcessId();
53+
@CheckForNull Integer processId = event.getParams().getProcessId();
5354
if (processId == null) {
5455
return;
5556
}
56-
parentProcessId = processId;
57-
}
5857

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

68-
boolean processIsAlive = ProcessHandle.of(parentProcessId)
69-
.map(ProcessHandle::isAlive)
70-
.orElse(false);
71-
72-
if (!processIsAlive) {
73-
LOGGER.error("Parent process with pid {} is not found. Closing application...", parentProcessId);
74-
languageServer.exit();
75-
}
63+
Optional.of(processId)
64+
.flatMap(ProcessHandle::of)
65+
.map(ProcessHandle::onExit)
66+
.ifPresent(onExitCallback -> onExitCallback.thenRun(() -> {
67+
LOGGER.warn("Parent process with pid {} is not found. Closing application...", processId);
68+
languageServer.exit();
69+
}));
7670
}
71+
7772
}

src/test/java/com/github/_1c_syntax/bsl/languageserver/ParentProcessWatcherTest.java

+27-17
Original file line numberDiff line numberDiff line change
@@ -25,53 +25,63 @@
2525
import org.eclipse.lsp4j.InitializeParams;
2626
import org.eclipse.lsp4j.services.LanguageServer;
2727
import org.junit.jupiter.api.Test;
28-
import org.mockito.InjectMocks;
29-
import org.mockito.Mock;
30-
import org.springframework.boot.test.context.SpringBootTest;
3128

29+
import java.io.IOException;
30+
import java.time.Duration;
31+
32+
import static org.awaitility.Awaitility.await;
33+
import static org.mockito.Mockito.mock;
3234
import static org.mockito.Mockito.never;
3335
import static org.mockito.Mockito.times;
3436
import static org.mockito.Mockito.verify;
3537

36-
@SpringBootTest
3738
class ParentProcessWatcherTest {
3839

39-
@InjectMocks
40-
private ParentProcessWatcher parentProcessWatcher;
41-
42-
@Mock
43-
private LanguageServer languageServer;
44-
4540
@Test
46-
void testParentProcessIsDead() {
41+
void testParentProcessIsDead() throws IOException, InterruptedException {
4742
// given
43+
var languageServer = mock(LanguageServer.class);
44+
var parentProcessWatcher = new ParentProcessWatcher(languageServer);
45+
4846
var params = new InitializeParams();
49-
params.setProcessId(-1);
47+
var process = new ProcessBuilder("timeout", "2").start();
48+
var pid = process.pid();
49+
params.setProcessId((int) pid);
5050

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

5454
// when
55-
parentProcessWatcher.watch();
55+
process.waitFor();
5656

5757
// then
58-
verify(languageServer, times(1)).exit();
58+
await()
59+
.atMost(Duration.ofSeconds(1))
60+
.untilAsserted(
61+
() -> verify(languageServer, times(1)).exit()
62+
);
5963
}
6064

6165
@Test
6266
void testParentProcessIsAlive() {
6367
// given
68+
var languageServer = mock(LanguageServer.class);
69+
var parentProcessWatcher = new ParentProcessWatcher(languageServer);
70+
6471
var params = new InitializeParams();
6572
params.setProcessId((int) ProcessHandle.current().pid());
6673

6774
var event = new LanguageServerInitializeRequestReceivedEvent(languageServer, params);
68-
parentProcessWatcher.handleEvent(event);
6975

7076
// when
71-
parentProcessWatcher.watch();
77+
parentProcessWatcher.handleEvent(event);
7278

7379
// then
74-
verify(languageServer, never()).exit();
80+
await()
81+
.atLeast(Duration.ofSeconds(1))
82+
.untilAsserted(
83+
() -> verify(languageServer, never()).exit()
84+
);
7585
}
7686

7787
}

0 commit comments

Comments
 (0)