AppName 限制不可重复;JobGoup本地缓存;

master
xuxueli 3 months ago
parent cf991ac505
commit fbfaf710cd

@ -2904,7 +2904,8 @@ alter table xxl_job_log
### 7.47 版本 v3.5.0 Release Notes[ING]
- 1、【新增】GLUE模式开关新增GLUE模式开关xxl.job.executor.glueenabled支持执行器维度设置是否启用GLUE模式
- 2、【TODO】执行器AccessToken执行器维度AccessToken线上化动态管理执行器间AccessToken隔离提升安全性
- 执行器 AccessToken:
- 执行器ExecutorBiz 服务处理、AdminBiz请求发起统一附加 appname + accessToken
- 调度中心AppName 限制不可重复JobGoup本地缓存
- 3、【TODO】调度中心OpenAPI增强提供任务管理能力封装Agent Skill并推送ClawHub
- 4、【TODO】配置线上化发送邮箱配置线上管理、线程池配置调整
- 5、【TODO】任务告警拆分“告警类型、告警配置”属性支持Webhook、邮箱多种方式

@ -17,7 +17,8 @@ CREATE TABLE `xxl_job_group`
`address_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '执行器地址类型0=自动注册、1=手动录入',
`address_list` text COMMENT '执行器地址列表,多地址逗号分隔',
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
PRIMARY KEY (`id`),
UNIQUE KEY `i_app_name` (`app_name`) USING BTREE
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;

@ -111,6 +111,11 @@ public class JobGroupController {
}
}
// valid appname duplicate
if (xxlJobGroupMapper.loadByAppname(xxlJobGroup.getAppname()) != null) {
return Response.ofFail("AppName "+I18nUtil.getString("system_repeat"));
}
// process
xxlJobGroup.setUpdateTime(new Date());
@ -123,15 +128,10 @@ public class JobGroupController {
@XxlSso(role = Consts.ADMIN_ROLE)
public Response<String> update(XxlJobGroup xxlJobGroup){
// valid appname
if (StringTool.isBlank(xxlJobGroup.getAppname())) {
return Response.ofFail((I18nUtil.getString("system_please_input")+"AppName") );
}
if (xxlJobGroup.getAppname().length()<4 || xxlJobGroup.getAppname().length()>64) {
return Response.ofFail( I18nUtil.getString("jobgroup_field_appname_length") );
}
if (XssUtil.hasXss(xxlJobGroup.getAppname())) {
return Response.ofFail( "AppName"+I18nUtil.getString("system_invalid") );
// load existing, appname not allowed to change
XxlJobGroup exists = xxlJobGroupMapper.load(xxlJobGroup.getId());
if (exists == null) {
return Response.ofFail(I18nUtil.getString("system_opt_error"));
}
// valid title

@ -24,6 +24,8 @@ public interface XxlJobGroupMapper {
public XxlJobGroup load(@Param("id") int id);
public XxlJobGroup loadByAppname(@Param("appname") String appname);
public List<XxlJobGroup> pageList(@Param("offset") int offset,
@Param("pagesize") int pagesize,
@Param("appname") String appname,

@ -76,4 +76,17 @@ public class XxlJobGroup {
this.addressList = addressList;
}
@Override
public String toString() {
return "XxlJobGroup{" +
"id=" + id +
", appname='" + appname + '\'' +
", title='" + title + '\'' +
", addressType=" + addressType +
", addressList='" + addressList + '\'' +
", updateTime=" + updateTime +
", registryList=" + registryList +
'}';
}
}

@ -7,7 +7,9 @@ import com.xxl.job.core.constant.Const;
import com.xxl.job.core.constant.RegistTypeEnum;
import com.xxl.job.core.openapi.admin.dto.RegistryRequest;
import com.xxl.tool.concurrent.CyclicThread;
import com.xxl.tool.core.CollectionTool;
import com.xxl.tool.core.StringTool;
import com.xxl.tool.json.GsonTool;
import com.xxl.tool.response.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -34,6 +36,12 @@ public class JobRegistryHelper {
*/
private CyclicThread registryMonitorThread;
/**
* job group cache
*/
private volatile Map<String, XxlJobGroup> appname2GroupCache = new ConcurrentHashMap<>();
private volatile Map<Integer, XxlJobGroup> id2GroupCache = new ConcurrentHashMap<>();
/**
* start
*/
@ -64,24 +72,24 @@ public class JobRegistryHelper {
registryMonitorThread = new CyclicThread("JobRegistryHelper#registryMonitorThread", true, new Runnable() {
@Override
public void run() {
// auto registry group
// 2.1、refresh auto-registry group
List<XxlJobGroup> groupList = XxlJobAdminBootstrap.getInstance().getXxlJobGroupMapper().findByAddressType(0);
if (groupList!=null && !groupList.isEmpty()) {
// remove dead address (admin/executor)
// a、remove dead address (admin/executor)
List<Integer> ids = XxlJobAdminBootstrap.getInstance().getXxlJobRegistryMapper().findDead(Const.DEAD_TIMEOUT, new Date());
if (ids!=null && !ids.isEmpty()) {
XxlJobAdminBootstrap.getInstance().getXxlJobRegistryMapper().removeDead(ids);
}
// fresh online address (admin/executor)
HashMap<String, List<String>> appAddressMap = new HashMap<String, List<String>>();
// b、fresh online address (appname List<address>)
HashMap<String, List<String>> appnameAddressMap = new HashMap<>();
List<XxlJobRegistry> list = XxlJobAdminBootstrap.getInstance().getXxlJobRegistryMapper().findAll(Const.DEAD_TIMEOUT, new Date());
if (list != null) {
for (XxlJobRegistry item: list) {
if (RegistTypeEnum.EXECUTOR.name().equals(item.getRegistryGroup())) {
String appname = item.getRegistryKey();
List<String> registryList = appAddressMap.get(appname);
List<String> registryList = appnameAddressMap.get(appname);
if (registryList == null) {
registryList = new ArrayList<String>();
}
@ -89,30 +97,46 @@ public class JobRegistryHelper {
if (!registryList.contains(item.getRegistryValue())) {
registryList.add(item.getRegistryValue());
}
appAddressMap.put(appname, registryList);
appnameAddressMap.put(appname, registryList);
}
}
}
// fresh group address
// c、write group address
for (XxlJobGroup group: groupList) {
List<String> registryList = appAddressMap.get(group.getAppname());
List<String> registryList = appnameAddressMap.get(group.getAppname());
// generate address list
String addressListStr = null;
if (registryList!=null && !registryList.isEmpty()) {
if (CollectionTool.isNotEmpty(registryList)) {
Collections.sort(registryList);
StringBuilder addressListSB = new StringBuilder();
for (String item:registryList) {
addressListSB.append(item).append(",");
}
addressListStr = addressListSB.toString();
addressListStr = addressListStr.substring(0, addressListStr.length()-1);
addressListStr = StringTool.join(registryList, ",");
}
// fill address
group.setAddressList(addressListStr);
group.setUpdateTime(new Date());
XxlJobAdminBootstrap.getInstance().getXxlJobGroupMapper().update(group);
}
}
// 2.2、refresh localcache
List<XxlJobGroup> jobGroupList = XxlJobAdminBootstrap.getInstance().getXxlJobGroupMapper().findAll();
Map<String, XxlJobGroup> appname2GroupCacheNew = new ConcurrentHashMap<>();
Map<Integer, XxlJobGroup> id2GroupCacheNew = new ConcurrentHashMap<>();
if (CollectionTool.isNotEmpty(jobGroupList)) {
for (XxlJobGroup group: jobGroupList) {
group.setUpdateTime(null);
appname2GroupCacheNew.put(group.getAppname(), group);
id2GroupCacheNew.put(group.getId(), group);
}
}
if (!GsonTool.toJson(appname2GroupCacheNew).equals(GsonTool.toJson(appname2GroupCache))) {
appname2GroupCache = appname2GroupCacheNew;
id2GroupCache = id2GroupCacheNew;
logger.info(">>>>>>>>>>> xxl-job, JobRegistryHelper, detect changes and refresh JobGroupCache success, appname2GroupCache:{}, id2GroupCache:{}", appname2GroupCache, id2GroupCache);
}
logger.debug(">>>>>>>>>>> xxl-job, JobRegistryHelper, refresh JobGroupCache success, appname2GroupCache:{}, id2GroupCache:{}", appname2GroupCache, id2GroupCache);
}
}, Const.BEAT_TIMEOUT * 1000L, true);
registryMonitorThread.start();
@ -200,5 +224,21 @@ public class JobRegistryHelper {
// Under consideration, prevent affecting core tables
}
// ---------------------- cache ----------------------
/**
* load JobGroup by id
*/
public XxlJobGroup load(int jobGroup){
return id2GroupCache.get(jobGroup);
}
/**
* load JobGroup by appname
*/
public XxlJobGroup loadByAppName(String appname){
return appname2GroupCache.get(appname);
}
}

@ -38,6 +38,7 @@ system_num_range=Numerical range limit
system_one=One
system_data=Data
system_selected_nothing=No data selected
system_repeat=Repeat
## tab
tab_opt=Tab Operation

@ -38,6 +38,7 @@ system_num_range=数值范围限制
system_one=一条
system_data=数据
system_selected_nothing=未选择
system_repeat=重复
## tab
tab_opt=页签操作

@ -38,6 +38,7 @@ system_num_range=數值範圍限制
system_one=一條
system_data=數據
system_selected_nothing=请選擇
system_repeat=重複
## tab
tab_opt=頁籤操作

@ -41,8 +41,7 @@
<update id="update" parameterType="com.xxl.job.admin.business.model.XxlJobGroup" >
UPDATE xxl_job_group
SET `app_name` = #{appname},
`title` = #{title},
SET `title` = #{title},
`address_type` = #{addressType},
`address_list` = #{addressList},
`update_time` = #{updateTime}
@ -60,6 +59,12 @@
WHERE t.id = #{id}
</select>
<select id="findByAppname" parameterType="java.lang.String" resultMap="XxlJobGroup">
SELECT <include refid="Base_Column_List" />
FROM xxl_job_group AS t
WHERE t.app_name = #{appname}
</select>
<select id="pageList" parameterType="java.util.HashMap" resultMap="XxlJobGroup">
SELECT <include refid="Base_Column_List" />
FROM xxl_job_group AS t

@ -139,7 +139,7 @@
<form class="form-horizontal form" role="form" >
<div class="form-group">
<label for="lastname" class="col-sm-2 control-label">AppName<font color="red">*</font></label>
<div class="col-sm-10"><input type="text" class="form-control" name="appname" placeholder="${I18n.system_please_input}AppName" maxlength="64" ></div>
<div class="col-sm-10"><input type="text" class="form-control" name="appname" placeholder="${I18n.system_please_input}AppName" maxlength="64" readonly ></div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_title}<font color="red">*</font></label>

Loading…
Cancel
Save