From 33647f20c27d2d5bb219b131399a54a3f965c1ef Mon Sep 17 00:00:00 2001 From: xuxueli <931591021@qq.com> Date: Sun, 21 Jun 2026 13:49:22 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E5=BA=A6=E4=B8=AD=E5=BF=83OpenAPI?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=EF=BC=9A=E6=8F=90=E4=BE=9B=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E8=83=BD=E5=8A=9B=EF=BC=8C=E5=8C=85=E6=8B=AC?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=96=B0=E5=BB=BA/=E6=9B=B4=E6=96=B0/?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E3=80=81=E5=90=AF=E5=8A=A8/=E5=81=9C?= =?UTF-8?q?=E6=AD=A2=E3=80=81=E4=BB=BB=E5=8A=A1=E8=A7=A6=E5=8F=91=E7=AD=89?= =?UTF-8?q?=EF=BC=9B=20=20=20=EF=BC=88=E6=B3=A8=E6=84=8F=EF=BC=9A=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E7=AE=A1=E7=90=86OpenAPI=E5=8F=8A=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=A4=BA=E4=BE=8B=EF=BC=8C=E8=AF=A6=E8=A7=81?= =?UTF-8?q?=E5=AE=98=E6=96=B9=E6=96=87=E6=A1=A3=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/XXL-JOB官方文档.md | 9 +- .../scheduler/openapi/OpenApiController.java | 32 ++++ .../service/impl/AdminJobBizImpl.java | 162 +++++++++++++++++ .../service/impl/XxlJobServiceImpl.java | 34 ++-- .../job/admin/framework/util/I18nUtil.java | 12 ++ .../com/xxl/job/openapi/AdminJobBizTest.java | 140 +++++++++++++++ .../xxl/job/core/openapi/admin/AdminBiz.java | 17 -- .../job/core/openapi/admin/AdminJobBiz.java | 46 +++++ .../core/openapi/admin/dto/JobAddRequest.java | 163 ++++++++++++++++++ .../openapi/admin/dto/JobOperateRequest.java | 24 +++ .../openapi/admin/dto/JobTriggerRequest.java | 42 +++++ .../openapi/admin/dto/JobUpdateRequest.java | 163 ++++++++++++++++++ 12 files changed, 809 insertions(+), 35 deletions(-) create mode 100644 xxl-job-admin/src/main/java/com/xxl/job/admin/business/service/impl/AdminJobBizImpl.java create mode 100644 xxl-job-admin/src/test/java/com/xxl/job/openapi/AdminJobBizTest.java create mode 100644 xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/AdminJobBiz.java create mode 100644 xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobAddRequest.java create mode 100644 xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobOperateRequest.java create mode 100644 xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobTriggerRequest.java create mode 100644 xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobUpdateRequest.java diff --git a/doc/XXL-JOB官方文档.md b/doc/XXL-JOB官方文档.md index b21d7ea8..d3eaba0e 100644 --- a/doc/XXL-JOB官方文档.md +++ b/doc/XXL-JOB官方文档.md @@ -2911,10 +2911,11 @@ alter table xxl_job_log ### 7.47 版本 v3.5.0 Release Notes[ING] - 1、【新增】GLUE模式开关:新增GLUE模式开关(xxl.job.executor.glueenabled),支持执行器维度设置是否启用GLUE模式; -- 2、【新增】执行器AccessToken:执行器维度隔离设置,提升安全性;线上化动态管理,提升操作效率及体验; -(注意:因为AccessToken调整为执行器维度,OpenAPI通讯协议部分发生变化,调度中心与执行器需要一并升级至v3.5.0;) -- 3、【调整】执行器约束规则调整,AppName限制不可重复; -- 4、【TODO】调度中心OpenAPI增强:提供任务管理能力,包括任务基础管理、状态启停、任务触发等; +- 2、【新增】AccessToken升级:支持执行期维度隔离设置,废弃旧的全局AccessToken,提升系统安全性; +(注意:因为AccessToken调整为执行器维度,OpenAPI通讯协议部分发生适配变化,调度中心与执行器需要一并升级至v3.5.0体验) +- 3、【新增】AccessToken管理:支持线上化动态管理,执行期管理UI界面可操作,提升操作效率及体验; +- 4、【新增】调度中心OpenAPI增强:提供任务管理能力,包括任务新建/更新/删除、启动/停止、任务触发等; + (注意:任务管理OpenAPI及操作代码示例,详见官方文档) - 5、【TODO】配置线上化:发送邮箱配置线上管理、线程池配置调整; - 6、【TODO】任务告警:拆分“告警类型、告警配置”属性,支持Webhook、邮箱多种方式; - 7、【TODO】任务说明:拆分“任务名称、任务备注”属性,前者用于任务检索,后者用于补充任务描述。 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/business/scheduler/openapi/OpenApiController.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/business/scheduler/openapi/OpenApiController.java index 6f01f7ea..4dc4f43a 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/business/scheduler/openapi/OpenApiController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/business/scheduler/openapi/OpenApiController.java @@ -4,7 +4,12 @@ import com.xxl.job.admin.business.model.XxlJobGroup; import com.xxl.job.admin.business.scheduler.config.XxlJobAdminBootstrap; import com.xxl.job.core.constant.Const; import com.xxl.job.core.openapi.admin.AdminBiz; +import com.xxl.job.core.openapi.admin.AdminJobBiz; import com.xxl.job.core.openapi.admin.dto.CallbackRequest; +import com.xxl.job.core.openapi.admin.dto.JobAddRequest; +import com.xxl.job.core.openapi.admin.dto.JobOperateRequest; +import com.xxl.job.core.openapi.admin.dto.JobTriggerRequest; +import com.xxl.job.core.openapi.admin.dto.JobUpdateRequest; import com.xxl.job.core.openapi.admin.dto.RegistryRequest; import com.xxl.sso.core.annotation.XxlSso; import com.xxl.tool.core.StringTool; @@ -24,6 +29,9 @@ public class OpenApiController { @Resource private AdminBiz adminBiz; + @Resource + private AdminJobBiz adminJobBiz; + /** * api */ @@ -71,6 +79,30 @@ public class OpenApiController { RegistryRequest registryParam = GsonTool.fromJson(requestBody, RegistryRequest.class); return adminBiz.registryRemove(registryParam); } + case "addJob": { + JobAddRequest jobParam = GsonTool.fromJson(requestBody, JobAddRequest.class); + return adminJobBiz.addJob(jobParam); + } + case "updateJob": { + JobUpdateRequest jobParam = GsonTool.fromJson(requestBody, JobUpdateRequest.class); + return adminJobBiz.updateJob(jobParam); + } + case "removeJob": { + JobOperateRequest jobParam = GsonTool.fromJson(requestBody, JobOperateRequest.class); + return adminJobBiz.removeJob(jobParam); + } + case "startJob": { + JobOperateRequest jobParam = GsonTool.fromJson(requestBody, JobOperateRequest.class); + return adminJobBiz.startJob(jobParam); + } + case "stopJob": { + JobOperateRequest jobParam = GsonTool.fromJson(requestBody, JobOperateRequest.class); + return adminJobBiz.stopJob(jobParam); + } + case "triggerJob": { + JobTriggerRequest jobParam = GsonTool.fromJson(requestBody, JobTriggerRequest.class); + return adminJobBiz.triggerJob(jobParam); + } default: return Response.ofFail("invalid request, uri-mapping("+ uri +") not found."); } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/business/service/impl/AdminJobBizImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/business/service/impl/AdminJobBizImpl.java new file mode 100644 index 00000000..25e3a95c --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/business/service/impl/AdminJobBizImpl.java @@ -0,0 +1,162 @@ +package com.xxl.job.admin.business.service.impl; + +import com.xxl.job.admin.business.model.XxlJobInfo; +import com.xxl.job.admin.business.service.XxlJobService; +import com.xxl.job.admin.framework.constant.Consts; +import com.xxl.job.core.openapi.admin.AdminJobBiz; +import com.xxl.job.core.openapi.admin.dto.JobAddRequest; +import com.xxl.job.core.openapi.admin.dto.JobOperateRequest; +import com.xxl.job.core.openapi.admin.dto.JobTriggerRequest; +import com.xxl.job.core.openapi.admin.dto.JobUpdateRequest; +import com.xxl.sso.core.model.LoginInfo; +import com.xxl.tool.concurrent.TokenBucket; +import com.xxl.tool.json.GsonTool; +import com.xxl.tool.response.Response; +import com.xxl.tool.response.ResponseCode; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.time.Duration; +import java.util.List; + +/** + * openapi admin job service, delegates to XxlJobService with a system-level LoginInfo + */ +@Service +public class AdminJobBizImpl implements AdminJobBiz { + + @Resource + private XxlJobService xxlJobService; + + /** + * openapi login info + */ + private final LoginInfo OPENAPI_LOGIN_INFO = new LoginInfo( + "0", + "openapi", + "OpenAPI", + null, + List.of(Consts.ADMIN_ROLE), + null, + -1L, + null); + + /** + * token bucket, for rate limiting + */ + private final TokenBucket tokenBucket = TokenBucket.create(3, Duration.ofSeconds(30)); + + @Override + public Response addJob(JobAddRequest request) { + + // rate limit + if (!tokenBucket.tryAcquire(1, Duration.ofMillis(1000L))) { + return Response.of(ResponseCode.CODE_502.getCode(), "Too many requests, please try again later."); + } + + // convert JobAddRequest to XxlJobInfo + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobGroup(request.getJobGroup()); + jobInfo.setJobDesc(request.getJobDesc()); + jobInfo.setAuthor(request.getAuthor()); + jobInfo.setAlarmEmail(request.getAlarmEmail()); + jobInfo.setScheduleType(request.getScheduleType()); + jobInfo.setScheduleConf(request.getScheduleConf()); + jobInfo.setMisfireStrategy(request.getMisfireStrategy()); + jobInfo.setExecutorRouteStrategy(request.getExecutorRouteStrategy()); + jobInfo.setExecutorHandler(request.getExecutorHandler()); + jobInfo.setExecutorParam(request.getExecutorParam()); + jobInfo.setExecutorBlockStrategy(request.getExecutorBlockStrategy()); + jobInfo.setExecutorTimeout(request.getExecutorTimeout()); + jobInfo.setExecutorFailRetryCount(request.getExecutorFailRetryCount()); + jobInfo.setGlueType(request.getGlueType()); + jobInfo.setGlueSource(request.getGlueSource()); + jobInfo.setGlueRemark(request.getGlueRemark()); + jobInfo.setChildJobId(null); + + // add job + return xxlJobService.add(jobInfo, OPENAPI_LOGIN_INFO); + } + + @Override + public Response updateJob(JobUpdateRequest request) { + + // rate limit + if (!tokenBucket.tryAcquire(1, Duration.ofMillis(1000L))) { + return Response.of(ResponseCode.CODE_502.getCode(), "Too many requests, please try again later."); + } + + // convert JobUpdateRequest to XxlJobInfo + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setId(request.getId()); + jobInfo.setJobGroup(0); + jobInfo.setJobDesc(request.getJobDesc()); + jobInfo.setAuthor(request.getAuthor()); + jobInfo.setAlarmEmail(request.getAlarmEmail()); + jobInfo.setScheduleType(request.getScheduleType()); + jobInfo.setScheduleConf(request.getScheduleConf()); + jobInfo.setMisfireStrategy(request.getMisfireStrategy()); + jobInfo.setExecutorRouteStrategy(request.getExecutorRouteStrategy()); + jobInfo.setExecutorHandler(request.getExecutorHandler()); + jobInfo.setExecutorParam(request.getExecutorParam()); + jobInfo.setExecutorBlockStrategy(request.getExecutorBlockStrategy()); + jobInfo.setExecutorTimeout(request.getExecutorTimeout()); + jobInfo.setExecutorFailRetryCount(request.getExecutorFailRetryCount()); + jobInfo.setGlueType(request.getGlueType()); + jobInfo.setGlueSource(request.getGlueSource()); + jobInfo.setGlueRemark(request.getGlueRemark()); + jobInfo.setChildJobId(null); + + // update job + return xxlJobService.update(jobInfo, OPENAPI_LOGIN_INFO); + } + + @Override + public Response removeJob(JobOperateRequest request) { + + // rate limit + if (!tokenBucket.tryAcquire(1, Duration.ofMillis(1000L))) { + return Response.of(ResponseCode.CODE_502.getCode(), "Too many requests, please try again later."); + } + + return xxlJobService.remove(request.getId(), OPENAPI_LOGIN_INFO); + } + + @Override + public Response startJob(JobOperateRequest request) { + + // rate limit + if (!tokenBucket.tryAcquire(1, Duration.ofMillis(1000L))) { + return Response.of(ResponseCode.CODE_502.getCode(), "Too many requests, please try again later."); + } + + return xxlJobService.start(request.getId(), OPENAPI_LOGIN_INFO); + } + + @Override + public Response stopJob(JobOperateRequest request) { + + // rate limit + if (!tokenBucket.tryAcquire(1, Duration.ofMillis(1000L))) { + return Response.of(ResponseCode.CODE_502.getCode(), "Too many requests, please try again later."); + } + + return xxlJobService.stop(request.getId(), OPENAPI_LOGIN_INFO); + } + + @Override + public Response triggerJob(JobTriggerRequest request) { + + // rate limit + if (!tokenBucket.tryAcquire(1, Duration.ofMillis(1000L))) { + return Response.of(ResponseCode.CODE_502.getCode(), "Too many requests, please try again later."); + } + + return xxlJobService.trigger( + OPENAPI_LOGIN_INFO, + request.getId(), + request.getExecutorParam(), + request.getAddressList()); + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/business/service/impl/XxlJobServiceImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/business/service/impl/XxlJobServiceImpl.java index 9c547fee..3cc4f3b3 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/business/service/impl/XxlJobServiceImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/business/service/impl/XxlJobServiceImpl.java @@ -69,10 +69,6 @@ public class XxlJobServiceImpl implements XxlJobService { public Response add(XxlJobInfo jobInfo, LoginInfo loginInfo) { // valid base - XxlJobGroup group = xxlJobGroupMapper.load(jobInfo.getJobGroup()); - if (group == null) { - return Response.ofFail (I18nUtil.getString("system_please_choose")+I18nUtil.getString("jobinfo_field_jobgroup")); - } if (StringTool.isBlank(jobInfo.getJobDesc())) { return Response.ofFail ( (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) ); } @@ -80,6 +76,12 @@ public class XxlJobServiceImpl implements XxlJobService { return Response.ofFail ( (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) ); } + // valid group + XxlJobGroup group = xxlJobGroupMapper.load(jobInfo.getJobGroup()); + if (group == null) { + return Response.ofFail (I18nUtil.getString("system_please_choose")+I18nUtil.getString("jobinfo_field_jobgroup")); + } + // valid trigger ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null); if (scheduleTypeEnum == null) { @@ -163,6 +165,7 @@ public class XxlJobServiceImpl implements XxlJobService { jobInfo.setGlueUpdatetime(new Date()); // remove the whitespace jobInfo.setExecutorHandler(jobInfo.getExecutorHandler().trim()); + xxlJobInfoMapper.save(jobInfo); if (jobInfo.getId() < 1) { return Response.ofFail ( (I18nUtil.getString("jobinfo_field_add")+I18nUtil.getString("system_fail")) ); @@ -186,6 +189,14 @@ public class XxlJobServiceImpl implements XxlJobService { return Response.ofFail ( (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) ); } + // valid group + if (jobInfo.getJobGroup() > 0) { + XxlJobGroup jobGroup = xxlJobGroupMapper.load(jobInfo.getJobGroup()); + if (jobGroup == null) { + return Response.ofFail ( (I18nUtil.getString("jobinfo_field_jobgroup")+I18nUtil.getString("system_invalid")) ); + } + } + // valid trigger ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null); if (scheduleTypeEnum == null) { @@ -258,12 +269,6 @@ public class XxlJobServiceImpl implements XxlJobService { jobInfo.setChildJobId(temp); } - // group valid - XxlJobGroup jobGroup = xxlJobGroupMapper.load(jobInfo.getJobGroup()); - if (jobGroup == null) { - return Response.ofFail ( (I18nUtil.getString("jobinfo_field_jobgroup")+I18nUtil.getString("system_invalid")) ); - } - // stage job info XxlJobInfo exists_jobInfo = xxlJobInfoMapper.loadById(jobInfo.getId()); if (exists_jobInfo == null) { @@ -288,7 +293,9 @@ public class XxlJobServiceImpl implements XxlJobService { } } - exists_jobInfo.setJobGroup(jobInfo.getJobGroup()); + if (jobInfo.getJobGroup() > 0) { + exists_jobInfo.setJobGroup(jobInfo.getJobGroup()); + } exists_jobInfo.setJobDesc(jobInfo.getJobDesc()); exists_jobInfo.setAuthor(jobInfo.getAuthor()); exists_jobInfo.setAlarmEmail(jobInfo.getAlarmEmail()); @@ -296,8 +303,7 @@ public class XxlJobServiceImpl implements XxlJobService { exists_jobInfo.setScheduleConf(jobInfo.getScheduleConf()); exists_jobInfo.setMisfireStrategy(jobInfo.getMisfireStrategy()); exists_jobInfo.setExecutorRouteStrategy(jobInfo.getExecutorRouteStrategy()); - // remove the whitespace - exists_jobInfo.setExecutorHandler(jobInfo.getExecutorHandler().trim()); + exists_jobInfo.setExecutorHandler(jobInfo.getExecutorHandler().trim()); // remove the whitespace exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam()); exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy()); exists_jobInfo.setExecutorTimeout(jobInfo.getExecutorTimeout()); @@ -334,7 +340,7 @@ public class XxlJobServiceImpl implements XxlJobService { // write operation log logger.info(">>>>>>>>>>> xxl-job operation log: operator = {}, type = {}, content = {}", - loginInfo.getUserName(), "jobinfo-remove", id); + loginInfo.getUserName(), "jobinfo-remove", GsonTool.toJson(xxlJobInfo)); return Response.ofSuccess(); } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/framework/util/I18nUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/framework/util/I18nUtil.java index 28bf19a4..791111e3 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/framework/util/I18nUtil.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/framework/util/I18nUtil.java @@ -90,6 +90,12 @@ public class I18nUtil implements InitializingBean { * @return */ public static String getString(String key) { + if (single==null) { + logger.debug(">>>>>>>>>>> xxl-job i18n fail, i18n not init."); + return null; + } + + // load return loadI18nProp().getProperty(key); } @@ -100,6 +106,12 @@ public class I18nUtil implements InitializingBean { * @return */ public static String getMultString(String... keys) { + if (single==null) { + logger.debug(">>>>>>>>>>> xxl-job i18n fail, i18n not init."); + return null; + } + + // build Map map = new HashMap<>(); Properties prop = loadI18nProp(); diff --git a/xxl-job-admin/src/test/java/com/xxl/job/openapi/AdminJobBizTest.java b/xxl-job-admin/src/test/java/com/xxl/job/openapi/AdminJobBizTest.java new file mode 100644 index 00000000..c5bbb52c --- /dev/null +++ b/xxl-job-admin/src/test/java/com/xxl/job/openapi/AdminJobBizTest.java @@ -0,0 +1,140 @@ +package com.xxl.job.openapi; + +import com.xxl.job.core.constant.Const; +import com.xxl.job.core.openapi.admin.AdminJobBiz; +import com.xxl.job.core.openapi.admin.dto.JobAddRequest; +import com.xxl.job.core.openapi.admin.dto.JobOperateRequest; +import com.xxl.job.core.openapi.admin.dto.JobTriggerRequest; +import com.xxl.job.core.openapi.admin.dto.JobUpdateRequest; +import com.xxl.tool.http.HttpTool; +import com.xxl.tool.response.Response; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * admin job api test + * + * @author xuxueli + */ +public class AdminJobBizTest { + private static final Logger logger = LoggerFactory.getLogger(AdminJobBizTest.class); + + private static String addressUrl = "http://127.0.0.1:8080"; + private static String accessToken = "default_token"; + private static String appname = "xxl-job-executor-sample"; + + private AdminJobBiz buildClient() { + String finalUrl = addressUrl + "/api"; + + return HttpTool.createClient() + .url(finalUrl) + .timeout(3 * 1000) + .header(Const.XXL_JOB_ACCESS_TOKEN, accessToken) + .header(Const.XXL_JOB_APPNAME, appname) + .proxy(AdminJobBiz.class); + } + + private int jobId = 10; + + @Test + public void jobAdd() throws Exception { + AdminJobBiz adminJobBiz = buildClient(); + + JobAddRequest request = new JobAddRequest(); + request.setJobGroup(1); + request.setJobDesc("openapi test job"); + request.setAuthor("openapi"); + request.setScheduleType("CRON"); + request.setScheduleConf("0/20 * * * * ?"); + request.setMisfireStrategy("DO_NOTHING"); + request.setExecutorRouteStrategy("FIRST"); + request.setExecutorHandler("demoJobHandler"); + request.setExecutorBlockStrategy("SERIAL_EXECUTION"); + request.setExecutorTimeout(0); + request.setExecutorFailRetryCount(0); + request.setGlueType("BEAN"); + + Response returnT = adminJobBiz.addJob(request); + assertTrue(returnT.isSuccess()); + assertNotNull(returnT.getData()); + jobId = Integer.parseInt(returnT.getData()); + logger.info("addJob jobId: {}", jobId); + } + + @Test + public void jobUpdate() throws Exception { + AdminJobBiz adminJobBiz = buildClient(); + + // update the job created by jobAdd (id should exist in test env) + JobUpdateRequest request = new JobUpdateRequest(); + request.setId(jobId); + request.setJobDesc("openapi test job update"); + request.setAuthor("openapi"); + request.setScheduleType("CRON"); + request.setScheduleConf("0/10 * * * * ?"); + request.setMisfireStrategy("DO_NOTHING"); + request.setExecutorRouteStrategy("FIRST"); + request.setExecutorHandler("demoJobHandler"); + request.setExecutorBlockStrategy("SERIAL_EXECUTION"); + request.setExecutorTimeout(0); + request.setExecutorFailRetryCount(0); + request.setGlueType("BEAN"); + + Response returnT = adminJobBiz.updateJob(request); + logger.info("updateJob response: {}", returnT); + assertTrue(returnT.isSuccess()); + } + + @Test + public void jobStart() throws Exception { + AdminJobBiz adminJobBiz = buildClient(); + + JobOperateRequest request = new JobOperateRequest(); + request.setId(jobId); + + Response returnT = adminJobBiz.startJob(request); + logger.info("startJob response: {}", returnT); + assertTrue(returnT.isSuccess()); + } + + @Test + public void jobStop() throws Exception { + AdminJobBiz adminJobBiz = buildClient(); + + JobOperateRequest request = new JobOperateRequest(); + request.setId(jobId); + + Response returnT = adminJobBiz.stopJob(request); + logger.info("stopJob response: {}", returnT); + assertTrue(returnT.isSuccess()); + } + + @Test + public void jobTrigger() throws Exception { + AdminJobBiz adminJobBiz = buildClient(); + + JobTriggerRequest request = new JobTriggerRequest(); + request.setId(jobId); + + Response returnT = adminJobBiz.triggerJob(request); + logger.info("triggerJob response: {}", returnT); + assertTrue(returnT.isSuccess()); + } + + @Test + public void jobRemove() throws Exception { + AdminJobBiz adminJobBiz = buildClient(); + + JobOperateRequest request = new JobOperateRequest(); + request.setId(jobId); + + Response returnT = adminJobBiz.removeJob(request); + logger.info("removeJob response: {}", returnT); + assertTrue(returnT.isSuccess()); + } + +} diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/AdminBiz.java b/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/AdminBiz.java index 227714fb..7f1515ee 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/AdminBiz.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/AdminBiz.java @@ -39,21 +39,4 @@ public interface AdminBiz { */ public Response registryRemove(RegistryRequest registryRequest); - - // ---------------------- job operate ---------------------- - - // jobAdd - - // jobUpdate - - // jobDelete - - // jobQuery - - // jobStart - - // jobStop - - // jobTrigger - } diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/AdminJobBiz.java b/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/AdminJobBiz.java new file mode 100644 index 00000000..ee5e90ee --- /dev/null +++ b/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/AdminJobBiz.java @@ -0,0 +1,46 @@ +package com.xxl.job.core.openapi.admin; + +import com.xxl.job.core.openapi.admin.dto.JobAddRequest; +import com.xxl.job.core.openapi.admin.dto.JobOperateRequest; +import com.xxl.job.core.openapi.admin.dto.JobTriggerRequest; +import com.xxl.job.core.openapi.admin.dto.JobUpdateRequest; +import com.xxl.tool.response.Response; + +/** + * openapi admin job interface for job lifecycle management + * + * @author xuxueli + */ +public interface AdminJobBiz { + + /** + * add a new job + */ + Response addJob(JobAddRequest request); + + /** + * update existing job config + */ + Response updateJob(JobUpdateRequest request); + + /** + * remove a job by id + */ + Response removeJob(JobOperateRequest request); + + /** + * start / enable a scheduled job + */ + Response startJob(JobOperateRequest request); + + /** + * stop / disable a scheduled job + */ + Response stopJob(JobOperateRequest request); + + /** + * trigger a job manually once + */ + Response triggerJob(JobTriggerRequest request); + +} diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobAddRequest.java b/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobAddRequest.java new file mode 100644 index 00000000..d73ef18e --- /dev/null +++ b/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobAddRequest.java @@ -0,0 +1,163 @@ +package com.xxl.job.core.openapi.admin.dto; + +import java.io.Serializable; + +/** + * request DTO for adding a new job + */ +public class JobAddRequest implements Serializable { + private static final long serialVersionUID = 42L; + + private int jobGroup; + private String jobDesc; + + private String author; + private String alarmEmail; + + private String scheduleType; // NONE、CRON、FIX_RATE + private String scheduleConf; + private String misfireStrategy; // DO_NOTHING、FIRE_ONCE_NOW + + private String executorRouteStrategy; // FIRST、LAST、ROUND、RANDOM、CONSISTENT_HASH、LEAST_FREQUENTLY_USED、LEAST_RECENTLY_USED、FAILOVER、BUSYOVER、SHARDING_BROADCAST + private String executorHandler; + private String executorParam; + private String executorBlockStrategy; // SERIAL_EXECUTION、DISCARD_LATER、COVER_EARLY + private int executorTimeout; + private int executorFailRetryCount; + + private String glueType; // BEAN、GLUE_GROOVY、GLUE_SHELL、GLUE_PYTHON、GLUE_NODEJS、GLUE_POWERSHELL、GLUE_PHP + private String glueSource; + private String glueRemark; + + public JobAddRequest() { + } + + public int getJobGroup() { + return jobGroup; + } + + public void setJobGroup(int jobGroup) { + this.jobGroup = jobGroup; + } + + public String getJobDesc() { + return jobDesc; + } + + public void setJobDesc(String jobDesc) { + this.jobDesc = jobDesc; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public String getScheduleType() { + return scheduleType; + } + + public void setScheduleType(String scheduleType) { + this.scheduleType = scheduleType; + } + + public String getScheduleConf() { + return scheduleConf; + } + + public void setScheduleConf(String scheduleConf) { + this.scheduleConf = scheduleConf; + } + + public String getMisfireStrategy() { + return misfireStrategy; + } + + public void setMisfireStrategy(String misfireStrategy) { + this.misfireStrategy = misfireStrategy; + } + + public String getExecutorRouteStrategy() { + return executorRouteStrategy; + } + + public void setExecutorRouteStrategy(String executorRouteStrategy) { + this.executorRouteStrategy = executorRouteStrategy; + } + + public String getExecutorHandler() { + return executorHandler; + } + + public void setExecutorHandler(String executorHandler) { + this.executorHandler = executorHandler; + } + + public String getExecutorParam() { + return executorParam; + } + + public void setExecutorParam(String executorParam) { + this.executorParam = executorParam; + } + + public String getExecutorBlockStrategy() { + return executorBlockStrategy; + } + + public void setExecutorBlockStrategy(String executorBlockStrategy) { + this.executorBlockStrategy = executorBlockStrategy; + } + + public int getExecutorTimeout() { + return executorTimeout; + } + + public void setExecutorTimeout(int executorTimeout) { + this.executorTimeout = executorTimeout; + } + + public int getExecutorFailRetryCount() { + return executorFailRetryCount; + } + + public void setExecutorFailRetryCount(int executorFailRetryCount) { + this.executorFailRetryCount = executorFailRetryCount; + } + + public String getGlueType() { + return glueType; + } + + public void setGlueType(String glueType) { + this.glueType = glueType; + } + + public String getGlueSource() { + return glueSource; + } + + public void setGlueSource(String glueSource) { + this.glueSource = glueSource; + } + + public String getGlueRemark() { + return glueRemark; + } + + public void setGlueRemark(String glueRemark) { + this.glueRemark = glueRemark; + } + +} diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobOperateRequest.java b/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobOperateRequest.java new file mode 100644 index 00000000..91205f54 --- /dev/null +++ b/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobOperateRequest.java @@ -0,0 +1,24 @@ +package com.xxl.job.core.openapi.admin.dto; + +import java.io.Serializable; + +/** + * request DTO for job operation (remove / start / stop) by id + */ +public class JobOperateRequest implements Serializable { + private static final long serialVersionUID = 42L; + + private int id; + + public JobOperateRequest() { + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + +} diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobTriggerRequest.java b/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobTriggerRequest.java new file mode 100644 index 00000000..98807c7e --- /dev/null +++ b/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobTriggerRequest.java @@ -0,0 +1,42 @@ +package com.xxl.job.core.openapi.admin.dto; + +import java.io.Serializable; + +/** + * request DTO for manually triggering a job once + */ +public class JobTriggerRequest implements Serializable { + private static final long serialVersionUID = 42L; + + private int id; + private String executorParam; + private String addressList; + + public JobTriggerRequest() { + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getExecutorParam() { + return executorParam; + } + + public void setExecutorParam(String executorParam) { + this.executorParam = executorParam; + } + + public String getAddressList() { + return addressList; + } + + public void setAddressList(String addressList) { + this.addressList = addressList; + } + +} diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobUpdateRequest.java b/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobUpdateRequest.java new file mode 100644 index 00000000..0174de6a --- /dev/null +++ b/xxl-job-core/src/main/java/com/xxl/job/core/openapi/admin/dto/JobUpdateRequest.java @@ -0,0 +1,163 @@ +package com.xxl.job.core.openapi.admin.dto; + +import java.io.Serializable; + +/** + * request DTO for updating an existing job + */ +public class JobUpdateRequest implements Serializable { + private static final long serialVersionUID = 42L; + + private int id; + private String jobDesc; + + private String author; + private String alarmEmail; + + private String scheduleType; + private String scheduleConf; + private String misfireStrategy; + + private String executorRouteStrategy; + private String executorHandler; + private String executorParam; + private String executorBlockStrategy; + private int executorTimeout; + private int executorFailRetryCount; + + private String glueType; + private String glueSource; + private String glueRemark; + + public JobUpdateRequest() { + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getJobDesc() { + return jobDesc; + } + + public void setJobDesc(String jobDesc) { + this.jobDesc = jobDesc; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public String getScheduleType() { + return scheduleType; + } + + public void setScheduleType(String scheduleType) { + this.scheduleType = scheduleType; + } + + public String getScheduleConf() { + return scheduleConf; + } + + public void setScheduleConf(String scheduleConf) { + this.scheduleConf = scheduleConf; + } + + public String getMisfireStrategy() { + return misfireStrategy; + } + + public void setMisfireStrategy(String misfireStrategy) { + this.misfireStrategy = misfireStrategy; + } + + public String getExecutorRouteStrategy() { + return executorRouteStrategy; + } + + public void setExecutorRouteStrategy(String executorRouteStrategy) { + this.executorRouteStrategy = executorRouteStrategy; + } + + public String getExecutorHandler() { + return executorHandler; + } + + public void setExecutorHandler(String executorHandler) { + this.executorHandler = executorHandler; + } + + public String getExecutorParam() { + return executorParam; + } + + public void setExecutorParam(String executorParam) { + this.executorParam = executorParam; + } + + public String getExecutorBlockStrategy() { + return executorBlockStrategy; + } + + public void setExecutorBlockStrategy(String executorBlockStrategy) { + this.executorBlockStrategy = executorBlockStrategy; + } + + public int getExecutorTimeout() { + return executorTimeout; + } + + public void setExecutorTimeout(int executorTimeout) { + this.executorTimeout = executorTimeout; + } + + public int getExecutorFailRetryCount() { + return executorFailRetryCount; + } + + public void setExecutorFailRetryCount(int executorFailRetryCount) { + this.executorFailRetryCount = executorFailRetryCount; + } + + public String getGlueType() { + return glueType; + } + + public void setGlueType(String glueType) { + this.glueType = glueType; + } + + public String getGlueSource() { + return glueSource; + } + + public void setGlueSource(String glueSource) { + this.glueSource = glueSource; + } + + public String getGlueRemark() { + return glueRemark; + } + + public void setGlueRemark(String glueRemark) { + this.glueRemark = glueRemark; + } + +}