mirror of
https://gitee.com/dromara/Jpom.git
synced 2024-12-02 11:58:01 +08:00
fix 修复 windows DSL 模式:另一个程序正在使用此文件,进程无法访问。 问题
This commit is contained in:
parent
84ddc27143
commit
ccf2b66cb8
@ -5,16 +5,17 @@
|
||||
### 🐣 新增功能
|
||||
|
||||
1. 【agent】新增 DSL 项目运行脚本环境变量配置(`run.start.scriptEnv`)
|
||||
2. 【agent】新增 DSL 项目自定义 `restart` 流程 `run.restart`
|
||||
2. 【agent】新增 DSL 项目自定义 `restart` 流程 (`run.restart`)
|
||||
|
||||
### 🐞 解决BUG、优化功能
|
||||
|
||||
1. 【agent】修复 DSL 项目重启操作被偶发异常(自动)关闭问题
|
||||
2. 【agent】优化 DSL 项目控制台日志输出格式
|
||||
3. 优化日志监听器:控制台支持自动重定向、第一次启动项目自动重新 showlog
|
||||
3. 【all】优化日志监听器:控制台支持自动重定向、第一次启动项目自动重新 showlog
|
||||
4. 【server】节点超时时间配置为 0 失效问题
|
||||
5. 【agent】修复进程列表在部分场景下进程号数字转换异常(@易自玉)
|
||||
6. 【agent】优化启动、停止、重启响应结果输出
|
||||
7. 【agent】修复 windows DSL 模式:`另一个程序正在使用此文件,进程无法访问。` 问题
|
||||
|
||||
------
|
||||
|
||||
|
@ -68,7 +68,6 @@ import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
@ -541,7 +540,7 @@ public abstract class AbstractProjectCommander {
|
||||
.map(s -> {
|
||||
int pid = ProjectCommanderUtil.parsePid(s);
|
||||
return CommandOpResult.of(pid > 0, s);
|
||||
}).orElse(null);
|
||||
}).orElseGet(() -> CommandOpResult.of(false, STOP_TAG));
|
||||
|
||||
} else {
|
||||
String tag = javaCopyItem == null ? nodeProjectInfoModel.getId() : javaCopyItem.getTagId();
|
||||
|
@ -25,16 +25,20 @@ package io.jpom.script;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUnit;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.io.LineHandler;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.jiangzeyin.common.spring.SpringUtil;
|
||||
import io.jpom.model.data.DslYmlDto;
|
||||
import io.jpom.model.data.NodeProjectInfoModel;
|
||||
import io.jpom.model.data.NodeScriptModel;
|
||||
import io.jpom.service.script.NodeScriptServer;
|
||||
import io.jpom.system.ConfigBean;
|
||||
import io.jpom.system.ExtConfigBean;
|
||||
import io.jpom.util.CommandUtil;
|
||||
import lombok.Setter;
|
||||
@ -59,6 +63,7 @@ public class DslScriptBuilder extends BaseRunScript implements Runnable {
|
||||
private final String args;
|
||||
private String action;
|
||||
private File scriptFile;
|
||||
private boolean autoDelete;
|
||||
private Map<String, String> environment;
|
||||
|
||||
private DslScriptBuilder(String action, Map<String, String> environment, String args, String log) {
|
||||
@ -166,6 +171,18 @@ public class DslScriptBuilder extends BaseRunScript implements Runnable {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
super.close();
|
||||
//
|
||||
if (autoDelete) {
|
||||
try {
|
||||
FileUtil.del(this.scriptFile);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步执行
|
||||
*
|
||||
@ -195,23 +212,33 @@ public class DslScriptBuilder extends BaseRunScript implements Runnable {
|
||||
NodeScriptServer nodeScriptServer = SpringUtil.getBean(NodeScriptServer.class);
|
||||
String scriptId = scriptProcess.getScriptId();
|
||||
NodeScriptModel item = nodeScriptServer.getItem(scriptId);
|
||||
Map<String, String> environment = DslScriptBuilder.environment(nodeProjectInfoModel);
|
||||
File scriptFile;
|
||||
boolean autoDelete = false;
|
||||
if (item == null) {
|
||||
scriptFile = FileUtil.file(nodeProjectInfoModel.allLib(), scriptId);
|
||||
Assert.state(FileUtil.isFile(scriptFile), "脚本模版不存在:" + scriptProcess.getScriptId());
|
||||
} else {
|
||||
scriptFile = DslScriptBuilder.initScriptFile(item, nodeProjectInfoModel);
|
||||
scriptFile = DslScriptBuilder.initScriptFile(item, environment);
|
||||
autoDelete = true;
|
||||
}
|
||||
DslScriptBuilder builder = new DslScriptBuilder(action, scriptProcess.getScriptEnv(), scriptProcess.getScriptArgs(), log);
|
||||
builder.putEnvironment(DslScriptBuilder.environment(nodeProjectInfoModel));
|
||||
builder.putEnvironment(environment);
|
||||
builder.setScriptFile(scriptFile);
|
||||
builder.setAutoDelete(autoDelete);
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static File initScriptFile(NodeScriptModel scriptModel, NodeProjectInfoModel nodeProjectInfoModel) {
|
||||
String id = nodeProjectInfoModel.getId();
|
||||
File scriptFile = scriptModel.scriptFile("_" + id);
|
||||
Map<String, String> dslEnv = environment(nodeProjectInfoModel);
|
||||
/**
|
||||
* 创建脚本文件
|
||||
*
|
||||
* @param scriptModel 脚本对象
|
||||
* @param dslEnv 环境变量
|
||||
* @return file
|
||||
*/
|
||||
private static File initScriptFile(NodeScriptModel scriptModel, Map<String, String> dslEnv) {
|
||||
String dataPath = ConfigBean.getInstance().getDataPath();
|
||||
File scriptFile = FileUtil.file(dataPath, ConfigBean.SCRIPT_RUN_CACHE_DIRECTORY, StrUtil.format("{}.{}", IdUtil.fastSimpleUUID(), CommandUtil.SUFFIX));
|
||||
// 替换内容
|
||||
String context = scriptModel.getContext();
|
||||
for (Map.Entry<String, String> envEntry : dslEnv.entrySet()) {
|
||||
@ -222,6 +249,33 @@ public class DslScriptBuilder extends BaseRunScript implements Runnable {
|
||||
return scriptFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理 脚本文件执行缓存
|
||||
*/
|
||||
public static void clearRunScript() {
|
||||
String dataPath = ConfigBean.getInstance().getDataPath();
|
||||
File scriptFile = FileUtil.file(dataPath, ConfigBean.SCRIPT_RUN_CACHE_DIRECTORY);
|
||||
if (!FileUtil.isDirectory(scriptFile)) {
|
||||
return;
|
||||
}
|
||||
File[] files = scriptFile.listFiles(pathname -> {
|
||||
Date lastModifiedTime = FileUtil.lastModifiedTime(pathname);
|
||||
DateTime now = DateTime.now();
|
||||
long between = DateUtil.between(lastModifiedTime, now, DateUnit.HOUR);
|
||||
// 文件大于一个小时才能被删除
|
||||
return between > 1;
|
||||
});
|
||||
if (files == null) {
|
||||
return;
|
||||
}
|
||||
for (File file : files) {
|
||||
try {
|
||||
FileUtil.del(file);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, String> environment(NodeProjectInfoModel nodeProjectInfoModel) {
|
||||
Map<String, String> dslEnv = new HashMap<>(10);
|
||||
dslEnv.put("PROJECT_ID", nodeProjectInfoModel.getId());
|
||||
|
@ -35,6 +35,7 @@ import io.jpom.common.RemoteVersion;
|
||||
import io.jpom.common.commander.AbstractProjectCommander;
|
||||
import io.jpom.cron.CronUtils;
|
||||
import io.jpom.model.data.NodeProjectInfoModel;
|
||||
import io.jpom.script.DslScriptBuilder;
|
||||
import io.jpom.service.manage.ProjectInfoService;
|
||||
import io.jpom.system.AgentExtConfigBean;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -121,8 +122,16 @@ public class AutoBackLog {
|
||||
private static void systemMonitor() {
|
||||
// 开启检测调度
|
||||
ThreadUtil.execute(() -> {
|
||||
CronUtils.upsert("system_monitor", "0 0 0,12 * * ?", RemoteVersion::loadRemoteInfo);
|
||||
RemoteVersion.loadRemoteInfo();
|
||||
// 定时任务
|
||||
CronUtils.upsert("system_monitor", "0 0 0,12 * * ?", AutoBackLog::systemTask);
|
||||
systemTask();
|
||||
});
|
||||
}
|
||||
|
||||
private static void systemTask() {
|
||||
// 启动加载
|
||||
RemoteVersion.loadRemoteInfo();
|
||||
// 清空脚本缓存
|
||||
DslScriptBuilder.clearRunScript();
|
||||
}
|
||||
}
|
||||
|
@ -44,170 +44,174 @@ import java.io.File;
|
||||
@Configuration
|
||||
public class ConfigBean {
|
||||
|
||||
/**
|
||||
* 用户名header
|
||||
*/
|
||||
public static final String JPOM_SERVER_USER_NAME = "Jpom-Server-UserName";
|
||||
/**
|
||||
* 用户名header
|
||||
*/
|
||||
public static final String JPOM_SERVER_USER_NAME = "Jpom-Server-UserName";
|
||||
|
||||
public static final String JPOM_AGENT_AUTHORIZE = "Jpom-Agent-Authorize";
|
||||
public static final String JPOM_AGENT_AUTHORIZE = "Jpom-Agent-Authorize";
|
||||
|
||||
public static final String DATA = "data";
|
||||
public static final String DATA = "data";
|
||||
|
||||
public static final int AUTHORIZE_ERROR = 900;
|
||||
/**
|
||||
* 脚本模板存放路径
|
||||
*/
|
||||
public static final String SCRIPT_DIRECTORY = "script";
|
||||
/**
|
||||
* 授权信息
|
||||
*/
|
||||
public static final String AUTHORIZE = "agent_authorize.json";
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static final String AUTHORIZE_USER_KEY = "jpom.authorize.agentName";
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static final String AUTHORIZE_AUTHORIZE_KEY = "jpom.authorize.agentPwd";
|
||||
/**
|
||||
* 程序升级信息文件
|
||||
*/
|
||||
public static final String UPGRADE = "upgrade.json";
|
||||
/**
|
||||
* 远程版本信息
|
||||
*/
|
||||
public static final String REMOTE_VERSION = "remote_version.json";
|
||||
/**
|
||||
* Jpom 程序运行的 application 标识
|
||||
*/
|
||||
@Value("${jpom.applicationTag:}")
|
||||
public String applicationTag;
|
||||
/**
|
||||
* 程序端口
|
||||
*/
|
||||
@Value("${server.port}")
|
||||
private int port;
|
||||
/**
|
||||
* 环境
|
||||
*/
|
||||
@Value("${" + ConfigFileApplicationListener.ACTIVE_PROFILES_PROPERTY + "}")
|
||||
private String active;
|
||||
/**
|
||||
* 数据目录缓存大小
|
||||
*/
|
||||
private long dataSizeCache;
|
||||
public static final int AUTHORIZE_ERROR = 900;
|
||||
/**
|
||||
* 脚本模板存放路径
|
||||
*/
|
||||
public static final String SCRIPT_DIRECTORY = "script";
|
||||
/**
|
||||
* 脚本默认运行缓存执行文件路径,考虑 windows 文件被占用情况
|
||||
*/
|
||||
public static final String SCRIPT_RUN_CACHE_DIRECTORY = "script_run_cache";
|
||||
/**
|
||||
* 授权信息
|
||||
*/
|
||||
public static final String AUTHORIZE = "agent_authorize.json";
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static final String AUTHORIZE_USER_KEY = "jpom.authorize.agentName";
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static final String AUTHORIZE_AUTHORIZE_KEY = "jpom.authorize.agentPwd";
|
||||
/**
|
||||
* 程序升级信息文件
|
||||
*/
|
||||
public static final String UPGRADE = "upgrade.json";
|
||||
/**
|
||||
* 远程版本信息
|
||||
*/
|
||||
public static final String REMOTE_VERSION = "remote_version.json";
|
||||
/**
|
||||
* Jpom 程序运行的 application 标识
|
||||
*/
|
||||
@Value("${jpom.applicationTag:}")
|
||||
public String applicationTag;
|
||||
/**
|
||||
* 程序端口
|
||||
*/
|
||||
@Value("${server.port}")
|
||||
private int port;
|
||||
/**
|
||||
* 环境
|
||||
*/
|
||||
@Value("${" + ConfigFileApplicationListener.ACTIVE_PROFILES_PROPERTY + "}")
|
||||
private String active;
|
||||
/**
|
||||
* 数据目录缓存大小
|
||||
*/
|
||||
private long dataSizeCache;
|
||||
|
||||
private volatile static ConfigBean configBean;
|
||||
private volatile static ConfigBean configBean;
|
||||
|
||||
/**
|
||||
* 单利模式
|
||||
*
|
||||
* @return config
|
||||
*/
|
||||
public static ConfigBean getInstance() {
|
||||
if (configBean == null) {
|
||||
synchronized (ConfigBean.class) {
|
||||
if (configBean == null) {
|
||||
configBean = SpringUtil.getBean(ConfigBean.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
return configBean;
|
||||
}
|
||||
/**
|
||||
* 单利模式
|
||||
*
|
||||
* @return config
|
||||
*/
|
||||
public static ConfigBean getInstance() {
|
||||
if (configBean == null) {
|
||||
synchronized (ConfigBean.class) {
|
||||
if (configBean == null) {
|
||||
configBean = SpringUtil.getBean(ConfigBean.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
return configBean;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取项目运行数据存储文件夹路径
|
||||
*
|
||||
* @return 文件夹路径
|
||||
*/
|
||||
public String getDataPath() {
|
||||
String dataPath = FileUtil.normalize(ExtConfigBean.getInstance().getPath() + StrUtil.SLASH + DATA);
|
||||
FileUtil.mkdir(dataPath);
|
||||
return dataPath;
|
||||
}
|
||||
/**
|
||||
* 获取项目运行数据存储文件夹路径
|
||||
*
|
||||
* @return 文件夹路径
|
||||
*/
|
||||
public String getDataPath() {
|
||||
String dataPath = FileUtil.normalize(ExtConfigBean.getInstance().getPath() + StrUtil.SLASH + DATA);
|
||||
FileUtil.mkdir(dataPath);
|
||||
return dataPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取pid文件
|
||||
*
|
||||
* @return file
|
||||
*/
|
||||
public File getPidFile() {
|
||||
return new File(getDataPath(), StrUtil.format("pid.{}.{}",
|
||||
JpomApplication.getAppType().name(), JpomManifest.getInstance().getPid()));
|
||||
}
|
||||
/**
|
||||
* 获取pid文件
|
||||
*
|
||||
* @return file
|
||||
*/
|
||||
public File getPidFile() {
|
||||
return new File(getDataPath(), StrUtil.format("pid.{}.{}",
|
||||
JpomApplication.getAppType().name(), JpomManifest.getInstance().getPid()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前项目全局 运行信息文件路径
|
||||
*
|
||||
* @param type 程序类型
|
||||
* @return file
|
||||
*/
|
||||
public File getApplicationJpomInfo(Type type) {
|
||||
return FileUtil.file(SystemUtil.getUserInfo().getTempDir(), "jpom", type.name());
|
||||
}
|
||||
/**
|
||||
* 获取当前项目全局 运行信息文件路径
|
||||
*
|
||||
* @param type 程序类型
|
||||
* @return file
|
||||
*/
|
||||
public File getApplicationJpomInfo(Type type) {
|
||||
return FileUtil.file(SystemUtil.getUserInfo().getTempDir(), "jpom", type.name());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 agent 端自动生成的授权文件路径
|
||||
*
|
||||
* @param dataPath 指定数据路径
|
||||
* @return file
|
||||
*/
|
||||
public String getAgentAutoAuthorizeFile(String dataPath) {
|
||||
return FileUtil.normalize(dataPath + StrUtil.SLASH + ConfigBean.AUTHORIZE);
|
||||
}
|
||||
/**
|
||||
* 获取 agent 端自动生成的授权文件路径
|
||||
*
|
||||
* @param dataPath 指定数据路径
|
||||
* @return file
|
||||
*/
|
||||
public String getAgentAutoAuthorizeFile(String dataPath) {
|
||||
return FileUtil.normalize(dataPath + StrUtil.SLASH + ConfigBean.AUTHORIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为 pro 模式运行
|
||||
*
|
||||
* @return pro
|
||||
*/
|
||||
public boolean isPro() {
|
||||
return StrUtil.equals(this.active, "pro");
|
||||
}
|
||||
/**
|
||||
* 是否为 pro 模式运行
|
||||
*
|
||||
* @return pro
|
||||
*/
|
||||
public boolean isPro() {
|
||||
return StrUtil.equals(this.active, "pro");
|
||||
}
|
||||
|
||||
public String getActive() {
|
||||
return active;
|
||||
}
|
||||
public String getActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取临时文件存储路径
|
||||
*
|
||||
* @return file
|
||||
*/
|
||||
public File getTempPath() {
|
||||
File file = new File(ConfigBean.getInstance().getDataPath());
|
||||
file = FileUtil.file(file, "temp");
|
||||
FileUtil.mkdir(file);
|
||||
return file;
|
||||
}
|
||||
/**
|
||||
* 获取临时文件存储路径
|
||||
*
|
||||
* @return file
|
||||
*/
|
||||
public File getTempPath() {
|
||||
File file = new File(ConfigBean.getInstance().getDataPath());
|
||||
file = FileUtil.file(file, "temp");
|
||||
FileUtil.mkdir(file);
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据目录大小
|
||||
*
|
||||
* @return byte
|
||||
*/
|
||||
public long dataSize() {
|
||||
String dataPath = getDataPath();
|
||||
long size = FileUtil.size(FileUtil.file(dataPath));
|
||||
dataSizeCache = size;
|
||||
return size;
|
||||
}
|
||||
/**
|
||||
* 数据目录大小
|
||||
*
|
||||
* @return byte
|
||||
*/
|
||||
public long dataSize() {
|
||||
String dataPath = getDataPath();
|
||||
long size = FileUtil.size(FileUtil.file(dataPath));
|
||||
dataSizeCache = size;
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取脚本模板路径
|
||||
*
|
||||
* @return file
|
||||
*/
|
||||
public File getScriptPath() {
|
||||
return FileUtil.file(this.getDataPath(), SCRIPT_DIRECTORY);
|
||||
}
|
||||
/**
|
||||
* 获取脚本模板路径
|
||||
*
|
||||
* @return file
|
||||
*/
|
||||
public File getScriptPath() {
|
||||
return FileUtil.file(this.getDataPath(), SCRIPT_DIRECTORY);
|
||||
}
|
||||
|
||||
public long getDataSizeCache() {
|
||||
return dataSizeCache;
|
||||
}
|
||||
public long getDataSizeCache() {
|
||||
return dataSizeCache;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user