mirror of
https://gitee.com/dromara/Jpom.git
synced 2024-12-02 20:08:40 +08:00
新增缓存管理查看定时任务执行统计
This commit is contained in:
parent
d76475c55b
commit
95958d9e69
@ -9,6 +9,7 @@
|
||||
3. 【server】新增系统配置-配置菜单是否显示,用于非超级管理员页面菜单控制
|
||||
4. 【server】新增节点统计功能,快速了解当前所有节点状态
|
||||
5. 【server】新增节点心跳检测配置`system.nodeHeartSecond`
|
||||
6. 新增缓存管理查看定时任务执行统计
|
||||
|
||||
### 解决BUG、优化功能
|
||||
|
||||
|
@ -22,14 +22,20 @@
|
||||
*/
|
||||
package io.jpom.cron;
|
||||
|
||||
import cn.hutool.core.date.SystemClock;
|
||||
import cn.hutool.cron.CronUtil;
|
||||
import cn.hutool.cron.Scheduler;
|
||||
import cn.hutool.cron.TaskExecutor;
|
||||
import cn.hutool.cron.TaskTable;
|
||||
import cn.hutool.cron.listener.TaskListener;
|
||||
import cn.hutool.cron.task.Task;
|
||||
import cn.jiangzeyin.common.DefaultSystemLog;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.jpom.system.ExtConfigBean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -39,6 +45,30 @@ import java.util.stream.Collectors;
|
||||
**/
|
||||
public class CronUtils {
|
||||
|
||||
private static final Map<String, TaskStat> TASK_STAT = new ConcurrentHashMap<>(50);
|
||||
|
||||
/**
|
||||
* 任务统计
|
||||
*/
|
||||
private static class TaskStat {
|
||||
/**
|
||||
* 执行次数
|
||||
*/
|
||||
private int executeCount;
|
||||
/**
|
||||
* 失败次数
|
||||
*/
|
||||
private int failedCount;
|
||||
/**
|
||||
* 成功次数
|
||||
*/
|
||||
private int succeedCount;
|
||||
/**
|
||||
* 最后执行时间
|
||||
*/
|
||||
private Long lastExecuteTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始
|
||||
*/
|
||||
@ -50,6 +80,27 @@ public class CronUtils {
|
||||
Scheduler scheduler = CronUtil.getScheduler();
|
||||
if (!scheduler.isStarted()) {
|
||||
CronUtil.start();
|
||||
scheduler.addListener(new TaskListener() {
|
||||
@Override
|
||||
public void onStart(TaskExecutor executor) {
|
||||
TaskStat taskStat = TASK_STAT.computeIfAbsent(executor.getCronTask().getId(), s -> new TaskStat());
|
||||
taskStat.lastExecuteTime = SystemClock.now();
|
||||
taskStat.executeCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSucceeded(TaskExecutor executor) {
|
||||
TaskStat taskStat = TASK_STAT.computeIfAbsent(executor.getCronTask().getId(), s -> new TaskStat());
|
||||
taskStat.succeedCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(TaskExecutor executor, Throwable exception) {
|
||||
TaskStat taskStat = TASK_STAT.computeIfAbsent(executor.getCronTask().getId(), s -> new TaskStat());
|
||||
taskStat.failedCount++;
|
||||
DefaultSystemLog.getLog().error("定时任务异常", exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,9 +114,16 @@ public class CronUtils {
|
||||
TaskTable taskTable = scheduler.getTaskTable();
|
||||
List<String> ids = taskTable.getIds();
|
||||
return ids.stream().map(s -> {
|
||||
TaskStat taskStat = TASK_STAT.get(s);
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("taskId", s);
|
||||
jsonObject.put("cron", scheduler.getPattern(s).toString());
|
||||
if (taskStat != null) {
|
||||
jsonObject.put("executeCount", taskStat.executeCount);
|
||||
jsonObject.put("failedCount", taskStat.failedCount);
|
||||
jsonObject.put("succeedCount", taskStat.succeedCount);
|
||||
jsonObject.put("lastExecuteTime", taskStat.lastExecuteTime);
|
||||
}
|
||||
return jsonObject;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
@ -22,7 +22,6 @@
|
||||
*/
|
||||
package io.jpom.controller.monitor;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.jiangzeyin.common.JsonMessage;
|
||||
import cn.jiangzeyin.common.validator.ValidatorConfig;
|
||||
@ -45,7 +44,6 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@ -84,7 +82,6 @@ public class MonitorListController extends BaseServerController {
|
||||
* @return json
|
||||
*/
|
||||
@RequestMapping(value = "getMonitorList", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
@Feature(method = MethodFeature.LIST)
|
||||
public String getMonitorList() {
|
||||
PageResultDto<MonitorModel> pageResultDto = monitorService.listPage(getRequest());
|
||||
@ -98,7 +95,6 @@ public class MonitorListController extends BaseServerController {
|
||||
* @return json
|
||||
*/
|
||||
@RequestMapping(value = "deleteMonitor", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
@Feature(method = MethodFeature.DEL)
|
||||
public String deleteMonitor(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "删除失败") String id) throws SQLException {
|
||||
//
|
||||
@ -121,7 +117,6 @@ public class MonitorListController extends BaseServerController {
|
||||
* @return json
|
||||
*/
|
||||
@RequestMapping(value = "updateMonitor", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
@Feature(method = MethodFeature.EDIT)
|
||||
public String updateMonitor(String id,
|
||||
@ValidatorConfig(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "监控名称不能为空")) String name,
|
||||
@ -170,33 +165,32 @@ public class MonitorListController extends BaseServerController {
|
||||
return JsonMessage.getString(200, "修改成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启或关闭监控
|
||||
*
|
||||
* @param id id
|
||||
* @param status 状态
|
||||
* @param type 类型
|
||||
* @return json
|
||||
*/
|
||||
@RequestMapping(value = "changeStatus", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
@Feature(method = MethodFeature.EDIT)
|
||||
public String changeStatus(@ValidatorConfig(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "id不能为空")) String id,
|
||||
String status, String type) {
|
||||
MonitorModel monitorModel = monitorService.getByKey(id);
|
||||
Assert.notNull(monitorModel, "不存在监控项啦");
|
||||
|
||||
boolean bStatus = Convert.toBool(status, false);
|
||||
if ("status".equalsIgnoreCase(type)) {
|
||||
monitorModel.setStatus(bStatus);
|
||||
} else if ("restart".equalsIgnoreCase(type)) {
|
||||
monitorModel.setAutoRestart(bStatus);
|
||||
} else {
|
||||
return JsonMessage.getString(405, "type不正确");
|
||||
}
|
||||
monitorService.updateById(monitorModel);
|
||||
return JsonMessage.getString(200, "修改成功");
|
||||
}
|
||||
// /**
|
||||
// * 开启或关闭监控
|
||||
// *
|
||||
// * @param id id
|
||||
// * @param status 状态
|
||||
// * @param type 类型
|
||||
// * @return json
|
||||
// */
|
||||
// @RequestMapping(value = "changeStatus", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
// @Feature(method = MethodFeature.EDIT)
|
||||
// public String changeStatus(@ValidatorConfig(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "id不能为空")) String id,
|
||||
// String status, String type) {
|
||||
// MonitorModel monitorModel = monitorService.getByKey(id);
|
||||
// Assert.notNull(monitorModel, "不存在监控项啦");
|
||||
//
|
||||
// boolean bStatus = Convert.toBool(status, false);
|
||||
// if ("status".equalsIgnoreCase(type)) {
|
||||
// monitorModel.setStatus(bStatus);
|
||||
// } else if ("restart".equalsIgnoreCase(type)) {
|
||||
// monitorModel.setAutoRestart(bStatus);
|
||||
// } else {
|
||||
// return JsonMessage.getString(405, "type不正确");
|
||||
// }
|
||||
// monitorService.updateById(monitorModel);
|
||||
// return JsonMessage.getString(200, "修改成功");
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import java.util.List;
|
||||
*/
|
||||
@TableName(value = "MONITOR_INFO", name = "监控信息")
|
||||
public class MonitorModel extends BaseWorkspaceModel {
|
||||
|
||||
private String name;
|
||||
/**
|
||||
* 监控的项目
|
||||
@ -54,6 +55,7 @@ public class MonitorModel extends BaseWorkspaceModel {
|
||||
/**
|
||||
* 监控周期
|
||||
*/
|
||||
@Deprecated
|
||||
private Integer cycle;
|
||||
|
||||
/**
|
||||
@ -73,11 +75,12 @@ public class MonitorModel extends BaseWorkspaceModel {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
public Integer getCycle() {
|
||||
return cycle;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setCycle(Integer cycle) {
|
||||
this.cycle = cycle;
|
||||
}
|
||||
|
@ -14,8 +14,8 @@
|
||||
<a-tooltip slot="name" slot-scope="text" placement="topLeft" :title="text">
|
||||
<span>{{ text }}</span>
|
||||
</a-tooltip>
|
||||
<a-switch slot="status" slot-scope="text" :checked="text" checked-children="开启" un-checked-children="关闭" />
|
||||
<a-switch slot="autoRestart" slot-scope="text" :checked="text" checked-children="是" un-checked-children="否" />
|
||||
<a-switch slot="status" slot-scope="text" :checked="text" disabled checked-children="开启" un-checked-children="关闭" />
|
||||
<a-switch slot="autoRestart" slot-scope="text" :checked="text" disabled checked-children="是" un-checked-children="否" />
|
||||
<a-switch slot="alarm" slot-scope="text" :checked="text" disabled checked-children="报警中" un-checked-children="未报警" />
|
||||
<a-tooltip slot="parent" slot-scope="text" placement="topLeft" :title="text">
|
||||
<span>{{ text }}</span>
|
||||
@ -33,12 +33,21 @@
|
||||
<a-form-model-item label="监控名称" prop="name">
|
||||
<a-input v-model="temp.name" placeholder="监控名称" />
|
||||
</a-form-model-item>
|
||||
|
||||
<a-form-model-item label="开启状态" prop="status">
|
||||
<a-switch v-model="temp.status" checked-children="开" un-checked-children="关" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="自动重启" prop="autoRestart">
|
||||
<a-switch v-model="temp.autoRestart" checked-children="开" un-checked-children="关" />
|
||||
<a-space size="large">
|
||||
<a-switch v-model="temp.status" checked-children="开" un-checked-children="关" />
|
||||
<div>
|
||||
自动重启:
|
||||
<a-switch v-model="temp.autoRestart" checked-children="开" un-checked-children="关" />
|
||||
</div>
|
||||
</a-space>
|
||||
</a-form-model-item>
|
||||
|
||||
<!-- <a-form-model-item label="自动重启" prop="autoRestart">
|
||||
|
||||
</a-form-model-item> -->
|
||||
|
||||
<a-form-model-item label="监控周期" prop="cycle">
|
||||
<a-radio-group v-model="temp.cycle" name="cycle">
|
||||
<a-radio :value="1">1 分钟</a-radio>
|
||||
@ -54,7 +63,7 @@
|
||||
</a-form-model-item>
|
||||
<a-form-model-item prop="notifyUser" class="jpom-notify">
|
||||
<template slot="label">
|
||||
报警联系人
|
||||
联系人
|
||||
<a-tooltip v-show="!temp.id">
|
||||
<template slot="title"> 如果这里的报警联系人无法选择,说明这里面的管理员没有设置邮箱,在右上角下拉菜单里面的用户资料里可以设置。 </template>
|
||||
<a-icon type="question-circle" theme="filled" />
|
||||
@ -337,7 +346,4 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.filter {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
|
@ -33,22 +33,21 @@
|
||||
</a-timeline-item>
|
||||
<a-timeline-item>
|
||||
<span class="layui-elem-quote">运行中的定时任务</span>
|
||||
<a-list v-if="taskList && taskList.length" bordered :data-source="taskList">
|
||||
<a-list-item slot="renderItem" slot-scope="item">
|
||||
<a-list-item-meta :description="item.taskId">
|
||||
<a slot="title"> {{ item.id }}</a>
|
||||
</a-list-item-meta>
|
||||
<div>
|
||||
{{ item.cron }}
|
||||
</div>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
<a-table rowKey="taskId" :columns="taskColumns" :data-source="taskList" :pagination="false">
|
||||
<a-tooltip slot="tooltip" slot-scope="text" placement="topLeft" :title="text">
|
||||
<span>{{ text }}</span>
|
||||
</a-tooltip>
|
||||
<a-tooltip slot="time" slot-scope="text" placement="topLeft" :title="parseTime(text)">
|
||||
<span>{{ parseTime(text) }}</span>
|
||||
</a-tooltip>
|
||||
</a-table>
|
||||
</a-timeline-item>
|
||||
</a-timeline>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getNodeCache, clearCache } from "@/api/system";
|
||||
import { parseTime } from "@/utils/time";
|
||||
export default {
|
||||
props: {
|
||||
node: {
|
||||
@ -59,12 +58,74 @@ export default {
|
||||
return {
|
||||
temp: {},
|
||||
taskList: [],
|
||||
taskColumns: [
|
||||
{
|
||||
title: "任务ID",
|
||||
dataIndex: "taskId",
|
||||
defaultSortOrder: "descend",
|
||||
sorter: (a, b) => a.taskId - b.taskId,
|
||||
ellipsis: true,
|
||||
scopedSlots: { customRender: "tooltip" },
|
||||
filters: [
|
||||
{
|
||||
text: "构建",
|
||||
value: "build",
|
||||
},
|
||||
{
|
||||
text: "节点脚本",
|
||||
value: "script",
|
||||
},
|
||||
{
|
||||
text: "服务端脚本",
|
||||
value: "server_script",
|
||||
},
|
||||
{
|
||||
text: "ssh 脚本",
|
||||
value: "ssh_command",
|
||||
},
|
||||
],
|
||||
onFilter: (value, record) => record.taskId.indexOf(value) === 0,
|
||||
},
|
||||
{
|
||||
title: "cron",
|
||||
dataIndex: "cron",
|
||||
sorter: (a, b) => a.cron.length - b.cron.length,
|
||||
sortDirections: ["descend", "ascend"],
|
||||
},
|
||||
{
|
||||
title: "执行次数",
|
||||
dataIndex: "executeCount",
|
||||
sortDirections: ["descend", "ascend"],
|
||||
sorter: (a, b) => a.executeCount || 0 - b.executeCount || 0,
|
||||
},
|
||||
{
|
||||
title: "成功次数",
|
||||
dataIndex: "succeedCount",
|
||||
sortDirections: ["descend", "ascend"],
|
||||
sorter: (a, b) => a.succeedCount || 0 - b.succeedCount || 0,
|
||||
},
|
||||
{
|
||||
title: "失败次数",
|
||||
dataIndex: "failedCount",
|
||||
sortDirections: ["descend", "ascend"],
|
||||
sorter: (a, b) => a.failedCount || 0 - b.failedCount || 0,
|
||||
},
|
||||
{
|
||||
title: "最后一次执行时间",
|
||||
dataIndex: "lastExecuteTime",
|
||||
sortDirections: ["descend", "ascend"],
|
||||
sorter: (a, b) => a.lastExecuteTime || 0 - b.lastExecuteTime || 0,
|
||||
ellipsis: true,
|
||||
scopedSlots: { customRender: "time" },
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
parseTime: parseTime,
|
||||
// load data
|
||||
loadData() {
|
||||
getNodeCache(this.node.id).then((res) => {
|
||||
|
@ -96,7 +96,13 @@ export default {
|
||||
return {
|
||||
loading: false,
|
||||
statusMap: status,
|
||||
listQuery: Object.assign({}, PAGE_DEFAULT_LIST_QUERY),
|
||||
listQuery: Object.assign(
|
||||
{
|
||||
order: "descend",
|
||||
order_field: "networkTime",
|
||||
},
|
||||
PAGE_DEFAULT_LIST_QUERY
|
||||
),
|
||||
list: [],
|
||||
statusStatMap: {},
|
||||
openStatusMap: {},
|
||||
@ -111,7 +117,7 @@ export default {
|
||||
{ title: "disk", dataIndex: "occupyDisk", sorter: true, key: "occupyDisk", ellipsis: true, scopedSlots: { customRender: "progress" } },
|
||||
{ title: "memory", dataIndex: "occupyMemory", sorter: true, key: "occupyMemory", ellipsis: true, scopedSlots: { customRender: "progress" } },
|
||||
{ title: "memoryUsed", dataIndex: "occupyMemoryUsed", sorter: true, key: "occupyMemoryUsed", ellipsis: true, scopedSlots: { customRender: "progress" } },
|
||||
{ title: "延迟(ms)", width: 100, dataIndex: "networkTime", sorter: true, key: "networkTime", ellipsis: true, scopedSlots: { customRender: "tooltipStatus" } },
|
||||
{ title: "延迟(ms)", width: 100, dataIndex: "networkTime", defaultSortOrder: "descend", sorter: true, key: "networkTime", ellipsis: true, scopedSlots: { customRender: "tooltipStatus" } },
|
||||
{ title: "运行时间", dataIndex: "upTimeStr", sorter: true, key: "upTimeStr", ellipsis: true, scopedSlots: { customRender: "tooltipStatus" } },
|
||||
{ title: "状态", width: 100, dataIndex: "status", sorter: true, key: "status", ellipsis: true, scopedSlots: { customRender: "status" } },
|
||||
{
|
||||
|
@ -28,33 +28,94 @@
|
||||
</a-timeline-item>
|
||||
<a-timeline-item>
|
||||
<span class="layui-elem-quote">运行中的定时任务</span>
|
||||
<a-list v-if="taskList && taskList.length" bordered :data-source="taskList">
|
||||
<a-list-item slot="renderItem" slot-scope="item">
|
||||
<a-list-item-meta :description="item.taskId">
|
||||
<a slot="title"> {{ item.id }}</a>
|
||||
</a-list-item-meta>
|
||||
<div>
|
||||
{{ item.cron }}
|
||||
</div>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
<a-table rowKey="taskId" :columns="taskColumns" :data-source="taskList" :pagination="false">
|
||||
<a-tooltip slot="tooltip" slot-scope="text" placement="topLeft" :title="text">
|
||||
<span>{{ text }}</span>
|
||||
</a-tooltip>
|
||||
<a-tooltip slot="time" slot-scope="text" placement="topLeft" :title="parseTime(text)">
|
||||
<span>{{ parseTime(text) }}</span>
|
||||
</a-tooltip>
|
||||
</a-table>
|
||||
</a-timeline-item>
|
||||
</a-timeline>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getServerCache, clearCache } from "@/api/system";
|
||||
import { parseTime } from "@/utils/time";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
temp: {},
|
||||
taskList: [],
|
||||
taskColumns: [
|
||||
{
|
||||
title: "任务ID",
|
||||
dataIndex: "taskId",
|
||||
defaultSortOrder: "descend",
|
||||
sorter: (a, b) => a.localeCompare(b, "zh-CN"),
|
||||
scopedSlots: { customRender: "tooltip" },
|
||||
ellipsis: true,
|
||||
filters: [
|
||||
{
|
||||
text: "构建",
|
||||
value: "build",
|
||||
},
|
||||
{
|
||||
text: "节点脚本",
|
||||
value: "script",
|
||||
},
|
||||
{
|
||||
text: "服务端脚本",
|
||||
value: "server_script",
|
||||
},
|
||||
{
|
||||
text: "ssh 脚本",
|
||||
value: "ssh_command",
|
||||
},
|
||||
],
|
||||
onFilter: (value, record) => record.taskId.indexOf(value) === 0,
|
||||
},
|
||||
{
|
||||
title: "cron",
|
||||
dataIndex: "cron",
|
||||
sorter: (a, b) => a.localeCompare(b, "zh-CN"),
|
||||
sortDirections: ["descend", "ascend"],
|
||||
},
|
||||
{
|
||||
title: "执行次数",
|
||||
dataIndex: "executeCount",
|
||||
sortDirections: ["descend", "ascend"],
|
||||
sorter: (a, b) => a.executeCount || 0 - b.executeCount || 0,
|
||||
},
|
||||
{
|
||||
title: "成功次数",
|
||||
dataIndex: "succeedCount",
|
||||
sortDirections: ["descend", "ascend"],
|
||||
sorter: (a, b) => a.succeedCount || 0 - b.succeedCount || 0,
|
||||
},
|
||||
{
|
||||
title: "失败次数",
|
||||
dataIndex: "failedCount",
|
||||
sortDirections: ["descend", "ascend"],
|
||||
sorter: (a, b) => a.failedCount || 0 - b.failedCount || 0,
|
||||
},
|
||||
{
|
||||
title: "最后一次执行时间",
|
||||
dataIndex: "lastExecuteTime",
|
||||
sortDirections: ["descend", "ascend"],
|
||||
sorter: (a, b) => a.lastExecuteTime || 0 - b.lastExecuteTime || 0,
|
||||
scopedSlots: { customRender: "time" },
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.loadData();
|
||||
// console.log(Comparator);
|
||||
},
|
||||
methods: {
|
||||
parseTime: parseTime,
|
||||
// load data
|
||||
loadData() {
|
||||
getServerCache().then((res) => {
|
||||
|
@ -84,6 +84,10 @@ export const CRON_DATA_SOURCE = [
|
||||
title: "1分钟",
|
||||
value: "0 0/1 * * * ?",
|
||||
},
|
||||
{
|
||||
title: "5分钟",
|
||||
value: "0 0/5 * * * ?",
|
||||
},
|
||||
{
|
||||
title: "10分钟",
|
||||
value: "0 0/10 * * * ?",
|
||||
@ -127,6 +131,10 @@ export const CRON_DATA_SOURCE = [
|
||||
title: "10秒一次",
|
||||
value: "0/10 * * * * ?",
|
||||
},
|
||||
{
|
||||
title: "30秒一次",
|
||||
value: "0/30 * * * * ?",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
Loading…
Reference in New Issue
Block a user