fix 关闭 Process 方式

This commit is contained in:
bwcx_jzy 2024-01-04 09:29:44 +08:00
parent e955f59299
commit 9a24a256c6
No known key found for this signature in database
GPG Key ID: E187D6E9DDDE8C53
6 changed files with 192 additions and 7 deletions

View File

@ -6,6 +6,7 @@
1. 【server】优化 支持批量删除构建信息(感谢@奇奇)
2. 【server】修复 删除项目、删除分发检查关联构建失败问题
3. 【all】优化 关闭 Process 方式
------

View File

@ -196,7 +196,7 @@ public class AgentFreeWebSocketScriptHandle extends BaseAgentWebSocketHandle {
@Override
public void close() throws Exception {
IoUtil.close(inputStream);
Optional.ofNullable(process).ifPresent(Process::destroy);
CommandUtil.kill(process);
try {
FileUtil.del(this.scriptFile);
} catch (Exception ignored) {

View File

@ -30,6 +30,7 @@ import cn.hutool.core.io.IoUtil;
import cn.keepbx.jpom.log.ILogRecorder;
import org.dromara.jpom.JpomApplication;
import org.dromara.jpom.common.Const;
import org.dromara.jpom.util.CommandUtil;
import org.dromara.jpom.util.LogRecorder;
import java.io.File;
@ -110,7 +111,7 @@ public abstract class BaseRunScript implements AutoCloseable, ILogRecorder {
public void close() {
// windows 中不能正常关闭
IoUtil.close(inputStream);
Optional.ofNullable(process).ifPresent(Process::destroy);
CommandUtil.kill(process);
}
/**

View File

@ -38,6 +38,7 @@ import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
/**
@ -350,6 +351,18 @@ public class CommandUtil {
return false;
}
/**
* 执行脚本
*
* @param scriptFile 脚本文件
* @param baseDir 基础路径
* @param env 环境变量
* @param args 参数
* @param consumer 回调
* @return 退出码
* @throws IOException io
* @throws InterruptedException 异常
*/
public static int execWaitFor(File scriptFile, File baseDir, Map<String, String> env, String args, BiConsumer<String, Process> consumer) throws IOException, InterruptedException {
ProcessBuilder processBuilder = new ProcessBuilder();
//
@ -362,11 +375,13 @@ public class CommandUtil {
processBuilder.command(command);
Optional.ofNullable(baseDir).ifPresent(processBuilder::directory);
Map<String, String> environment = processBuilder.environment();
// 新增逻辑,将env和environment里value==null替换成空字符,防止putAll出现空指针报错
env.replaceAll((k, v) -> Optional.ofNullable(v).orElse(StrUtil.EMPTY));
environment.replaceAll((k, v) -> Optional.ofNullable(v).orElse(StrUtil.EMPTY));
// 环境变量
Optional.ofNullable(env).ifPresent(environment::putAll);
// 新增逻辑,将env和environment里value==null替换成空字符,防止putAll出现空指针报错
if (env != null) {
// 环境变量
env.replaceAll((k, v) -> Optional.ofNullable(v).orElse(StrUtil.EMPTY));
environment.putAll(env);
}
//
Process process = processBuilder.start();
try (InputStream inputStream = process.getInputStream()) {
@ -374,4 +389,35 @@ public class CommandUtil {
}
return process.waitFor();
}
/**
* 关闭 Process实例
*
* @param process Process
*/
public static void kill(Process process) {
if (process == null) {
return;
}
while (true) {
process.destroy();
if (process.isAlive()) {
Object handle = tryGetProcessId(process);
log.info("等待关闭进程:{}", handle);
process.destroyForcibly();
try {
process.waitFor(500, TimeUnit.MILLISECONDS);
} catch (InterruptedException ignored) {
}
} else {
break;
}
}
}
public static Object tryGetProcessId(Process process) {
Object handle = ReflectUtil.getFieldValue(process, "handle");
Object pid = ReflectUtil.getFieldValue(process, "pid");
return Optional.ofNullable(handle).orElse(pid);
}
}

View File

@ -197,7 +197,7 @@ public class BuildExecuteManage implements Runnable {
* 取消任务
*/
private void cancelTask(String desc) {
Optional.ofNullable(process).ifPresent(Process::destroy);
CommandUtil.kill(process);
Integer buildMode = taskData.buildInfoModel.getBuildMode();
if (buildMode != null && buildMode == 1) {
// 容器构建 删除容器

View File

@ -0,0 +1,137 @@
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.file.Tailer;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ReflectUtil;
import org.dromara.jpom.util.CommandUtil;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author bwcx_jzy
* @since 24/1/3 003
*/
public class TestProcess {
@Test
public void testWin() throws IOException {
AtomicReference<Process> start = new AtomicReference<>();
// 执行线程
Thread thread = new Thread(() -> {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.redirectErrorStream(true);
processBuilder.command("ping 127.0.0.1 -t".split(" "));
try {
start.set(processBuilder.start());
try (InputStream inputStream = start.get().getInputStream()) {
IoUtil.readLines(inputStream, CharsetUtil.CHARSET_GBK, new Tailer.ConsoleLineHandler());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
});
ThreadUtil.execute(thread);
while (true) {
Process process = start.get();
if (process != null) {
break;
}
// System.out.println("waiting...");
}
ThreadUtil.sleep(5, TimeUnit.SECONDS);
// 关闭线程
Thread thread2 = new Thread(() -> {
while (true) {
Process process = start.get();
if (process.isAlive()) {
process.destroy();
Object handle = ReflectUtil.getFieldValue(process, "handle");
System.out.println(handle);
try {
process.waitFor(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
} else {
System.out.println("成功终止");
break;
}
}
});
thread2.run();
}
@Test
public void testLinux() {
AtomicReference<Process> start = new AtomicReference<>();
AtomicBoolean running = new AtomicBoolean(true);
// 执行线程
Thread thread = new Thread(() -> {
running.set(true);
try {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.redirectErrorStream(true);
// String s = "cd /mnt/d/System-Data/Documents/jpom/server/data/build/5a68e19578654cb2965433584ce84f4c/source && mvn clean package";
String[] command = new String[]{"bash", "/home/user/test.sh"};
// String[] command = ArrayUtil.append(new String[]{"/bin/bash", "-c"}, s);
System.out.println(Arrays.toString(command));
processBuilder.command(command);
try {
start.set(processBuilder.start());
try (InputStream inputStream = start.get().getInputStream()) {
IoUtil.readLines(inputStream, CharsetUtil.CHARSET_UTF_8, new Tailer.ConsoleLineHandler());
}
int waitFor = start.get().waitFor();
System.out.println("线程结束:" + waitFor);
} catch (Exception e) {
e.printStackTrace();
}
} finally {
running.set(false);
}
});
ThreadUtil.execute(thread);
while (true) {
Process process = start.get();
if (process != null) {
break;
}
if (!running.get()) {
System.out.println("线程关闭");
break;
}
// System.out.println("waiting...");
}
Process process = start.get();
if (process == null) {
return;
}
ThreadUtil.sleep(20, TimeUnit.SECONDS);
// 关闭线程
Thread thread2 = new Thread(() -> {
while (true) {
if (process.isAlive()) {
Object handle = CommandUtil.tryGetProcessId(process);
System.out.println(handle);
process.destroy();
try {
process.waitFor(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
} else {
System.out.println("成功终止");
break;
}
}
});
thread2.run();
}
}