mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-11-04 09:01:37 +08:00 
			
		
		
		
	refactor(schedule): 重构任务调度模块,使用 OpenFeign 替代 WebClient
This commit is contained in:
		@@ -17,12 +17,12 @@
 | 
			
		||||
package top.continew.admin.schedule.api;
 | 
			
		||||
 | 
			
		||||
import com.aizuda.snailjob.common.core.model.Result;
 | 
			
		||||
import org.springframework.http.MediaType;
 | 
			
		||||
import org.springframework.http.ResponseEntity;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestBody;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestParam;
 | 
			
		||||
import org.springframework.web.service.annotation.*;
 | 
			
		||||
import org.springframework.cloud.openfeign.FeignClient;
 | 
			
		||||
import org.springframework.cloud.openfeign.SpringQueryMap;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
import top.continew.admin.schedule.config.FeignRequestInterceptor;
 | 
			
		||||
import top.continew.admin.schedule.model.JobPageResult;
 | 
			
		||||
import top.continew.admin.schedule.model.query.JobQuery;
 | 
			
		||||
import top.continew.admin.schedule.model.req.JobReq;
 | 
			
		||||
import top.continew.admin.schedule.model.req.JobStatusReq;
 | 
			
		||||
import top.continew.admin.schedule.model.req.JobTriggerReq;
 | 
			
		||||
@@ -38,25 +38,17 @@ import java.util.Set;
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 2024/6/25 18:20
 | 
			
		||||
 */
 | 
			
		||||
@HttpExchange(accept = MediaType.APPLICATION_JSON_VALUE)
 | 
			
		||||
@FeignClient(value = "job", url = "${snail-job.server.api.url}", path = "/job", configuration = FeignRequestInterceptor.class)
 | 
			
		||||
public interface JobApi {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 分页查询列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param groupName 任务组
 | 
			
		||||
     * @param jobName   任务名称
 | 
			
		||||
     * @param jobStatus 任务状态
 | 
			
		||||
     * @param page      页码
 | 
			
		||||
     * @param size      每页条数
 | 
			
		||||
     * @param query 查询条件
 | 
			
		||||
     * @return 响应信息
 | 
			
		||||
     */
 | 
			
		||||
    @GetExchange("/job/page/list")
 | 
			
		||||
    ResponseEntity<JobPageResult<List<JobResp>>> page(@RequestParam(value = "groupName", required = false) String groupName,
 | 
			
		||||
                                                      @RequestParam(value = "jobName", required = false) String jobName,
 | 
			
		||||
                                                      @RequestParam(value = "jobStatus", required = false) Integer jobStatus,
 | 
			
		||||
                                                      @RequestParam("page") int page,
 | 
			
		||||
                                                      @RequestParam("size") int size);
 | 
			
		||||
    @GetMapping("/page/list")
 | 
			
		||||
    JobPageResult<List<JobResp>> page(@SpringQueryMap JobQuery query);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 新增
 | 
			
		||||
@@ -64,8 +56,8 @@ public interface JobApi {
 | 
			
		||||
     * @param req 新增信息
 | 
			
		||||
     * @return 响应信息
 | 
			
		||||
     */
 | 
			
		||||
    @PostExchange("/job")
 | 
			
		||||
    ResponseEntity<Result<Boolean>> create(@RequestBody JobReq req);
 | 
			
		||||
    @PostMapping
 | 
			
		||||
    Result<Boolean> create(@RequestBody JobReq req);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 修改
 | 
			
		||||
@@ -73,8 +65,8 @@ public interface JobApi {
 | 
			
		||||
     * @param req 修改信息
 | 
			
		||||
     * @return 响应信息
 | 
			
		||||
     */
 | 
			
		||||
    @PutExchange("/job")
 | 
			
		||||
    ResponseEntity<Result<Boolean>> update(@RequestBody JobReq req);
 | 
			
		||||
    @PutMapping
 | 
			
		||||
    Result<Boolean> update(@RequestBody JobReq req);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 修改状态
 | 
			
		||||
@@ -82,8 +74,8 @@ public interface JobApi {
 | 
			
		||||
     * @param req 修改信息
 | 
			
		||||
     * @return 响应信息
 | 
			
		||||
     */
 | 
			
		||||
    @PutExchange("/job/status")
 | 
			
		||||
    ResponseEntity<Result<Boolean>> updateStatus(@RequestBody JobStatusReq req);
 | 
			
		||||
    @PutMapping("/status")
 | 
			
		||||
    Result<Boolean> updateStatus(@RequestBody JobStatusReq req);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除
 | 
			
		||||
@@ -91,8 +83,8 @@ public interface JobApi {
 | 
			
		||||
     * @param ids ID 列表
 | 
			
		||||
     * @return 响应信息
 | 
			
		||||
     */
 | 
			
		||||
    @DeleteExchange("/job/ids")
 | 
			
		||||
    ResponseEntity<Result<Boolean>> delete(@RequestBody Set<Long> ids);
 | 
			
		||||
    @DeleteMapping("/ids")
 | 
			
		||||
    Result<Boolean> delete(@RequestBody Set<Long> ids);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 执行
 | 
			
		||||
@@ -100,14 +92,6 @@ public interface JobApi {
 | 
			
		||||
     * @param req 参数
 | 
			
		||||
     * @return 响应信息
 | 
			
		||||
     */
 | 
			
		||||
    @PostExchange("/job/trigger")
 | 
			
		||||
    ResponseEntity<Result<Boolean>> trigger(@RequestBody JobTriggerReq req);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询分组列表
 | 
			
		||||
     *
 | 
			
		||||
     * @return 响应信息
 | 
			
		||||
     */
 | 
			
		||||
    @GetExchange("/group/all/group-name/list")
 | 
			
		||||
    ResponseEntity<Result<List<String>>> listGroup();
 | 
			
		||||
    @PostMapping("/trigger")
 | 
			
		||||
    Result<Boolean> trigger(@RequestBody JobTriggerReq req);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,15 +17,17 @@
 | 
			
		||||
package top.continew.admin.schedule.api;
 | 
			
		||||
 | 
			
		||||
import com.aizuda.snailjob.common.core.model.Result;
 | 
			
		||||
import org.springframework.http.MediaType;
 | 
			
		||||
import org.springframework.http.ResponseEntity;
 | 
			
		||||
import org.springframework.cloud.openfeign.FeignClient;
 | 
			
		||||
import org.springframework.cloud.openfeign.SpringQueryMap;
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.PathVariable;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestParam;
 | 
			
		||||
import org.springframework.web.service.annotation.GetExchange;
 | 
			
		||||
import org.springframework.web.service.annotation.HttpExchange;
 | 
			
		||||
import org.springframework.web.service.annotation.PostExchange;
 | 
			
		||||
import org.springframework.web.bind.annotation.PostMapping;
 | 
			
		||||
import top.continew.admin.schedule.config.FeignRequestInterceptor;
 | 
			
		||||
import top.continew.admin.schedule.model.JobInstanceLogPageResult;
 | 
			
		||||
import top.continew.admin.schedule.model.JobPageResult;
 | 
			
		||||
import top.continew.admin.schedule.model.query.JobInstanceLogQuery;
 | 
			
		||||
import top.continew.admin.schedule.model.query.JobInstanceQuery;
 | 
			
		||||
import top.continew.admin.schedule.model.query.JobLogQuery;
 | 
			
		||||
import top.continew.admin.schedule.model.resp.JobInstanceResp;
 | 
			
		||||
import top.continew.admin.schedule.model.resp.JobLogResp;
 | 
			
		||||
 | 
			
		||||
@@ -38,29 +40,17 @@ import java.util.List;
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 2024/6/27 23:03
 | 
			
		||||
 */
 | 
			
		||||
@HttpExchange(value = "/job", accept = MediaType.APPLICATION_JSON_VALUE)
 | 
			
		||||
@FeignClient(value = "job-batch", url = "${snail-job.server.api.url}", path = "/job", configuration = FeignRequestInterceptor.class)
 | 
			
		||||
public interface JobBatchApi {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 分页查询列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param jobId           任务 ID
 | 
			
		||||
     * @param jobName         任务名称
 | 
			
		||||
     * @param groupName       组名称
 | 
			
		||||
     * @param taskBatchStatus 任务批次状态
 | 
			
		||||
     * @param datetimeRange   时间范围
 | 
			
		||||
     * @param page            页码
 | 
			
		||||
     * @param size            每页条数
 | 
			
		||||
     * @param query 查询条件
 | 
			
		||||
     * @return 响应信息
 | 
			
		||||
     */
 | 
			
		||||
    @GetExchange("/batch/list")
 | 
			
		||||
    ResponseEntity<JobPageResult<List<JobLogResp>>> page(@RequestParam(value = "jobId", required = false) Long jobId,
 | 
			
		||||
                                                         @RequestParam(value = "jobName", required = false) String jobName,
 | 
			
		||||
                                                         @RequestParam(value = "groupName", required = false) String groupName,
 | 
			
		||||
                                                         @RequestParam(value = "taskBatchStatus", required = false) Integer taskBatchStatus,
 | 
			
		||||
                                                         @RequestParam(value = "datetimeRange", required = false) String[] datetimeRange,
 | 
			
		||||
                                                         @RequestParam(value = "page") Integer page,
 | 
			
		||||
                                                         @RequestParam(value = "size") Integer size);
 | 
			
		||||
    @GetMapping("/batch/list")
 | 
			
		||||
    JobPageResult<List<JobLogResp>> page(@SpringQueryMap JobLogQuery query);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 停止
 | 
			
		||||
@@ -68,8 +58,8 @@ public interface JobBatchApi {
 | 
			
		||||
     * @param id ID
 | 
			
		||||
     * @return 响应信息
 | 
			
		||||
     */
 | 
			
		||||
    @PostExchange("/batch/stop/{id}")
 | 
			
		||||
    ResponseEntity<Result<Boolean>> stop(@PathVariable("id") Long id);
 | 
			
		||||
    @PostMapping("/batch/stop/{id}")
 | 
			
		||||
    Result<Boolean> stop(@PathVariable("id") Long id);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 重试
 | 
			
		||||
@@ -77,40 +67,24 @@ public interface JobBatchApi {
 | 
			
		||||
     * @param id ID
 | 
			
		||||
     * @return 响应信息
 | 
			
		||||
     */
 | 
			
		||||
    @PostExchange("/batch/retry/{id}")
 | 
			
		||||
    ResponseEntity<Result<Boolean>> retry(@PathVariable("id") Long id);
 | 
			
		||||
    @PostMapping("/batch/retry/{id}")
 | 
			
		||||
    Result<Boolean> retry(@PathVariable("id") Long id);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 分页查询任务实例列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param jobId       任务 ID
 | 
			
		||||
     * @param taskBatchId 任务批次 ID
 | 
			
		||||
     * @param page        页码
 | 
			
		||||
     * @param size        每页条数
 | 
			
		||||
     * @param query 查询条件
 | 
			
		||||
     * @return 响应信息
 | 
			
		||||
     */
 | 
			
		||||
    @GetExchange("/task/list")
 | 
			
		||||
    ResponseEntity<JobPageResult<List<JobInstanceResp>>> pageTask(@RequestParam(value = "jobId", required = false) Long jobId,
 | 
			
		||||
                                                                  @RequestParam(value = "taskBatchId") Long taskBatchId,
 | 
			
		||||
                                                                  @RequestParam(value = "page") Integer page,
 | 
			
		||||
                                                                  @RequestParam(value = "size") Integer size);
 | 
			
		||||
    @GetMapping("/task/list")
 | 
			
		||||
    JobPageResult<List<JobInstanceResp>> pageTask(@SpringQueryMap JobInstanceQuery query);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 分页查询任务实例日志列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param jobId       任务 ID
 | 
			
		||||
     * @param taskBatchId 任务批次 ID
 | 
			
		||||
     * @param taskId      任务实例ID
 | 
			
		||||
     * @param startId     起始 ID
 | 
			
		||||
     * @param fromIndex   起始索引
 | 
			
		||||
     * @param size        每页条数
 | 
			
		||||
     * @param query 查询条件
 | 
			
		||||
     * @return 响应信息
 | 
			
		||||
     */
 | 
			
		||||
    @GetExchange("/log/list")
 | 
			
		||||
    ResponseEntity<Result<JobInstanceLogPageResult>> pageLog(@RequestParam(value = "jobId", required = false) Long jobId,
 | 
			
		||||
                                                             @RequestParam(value = "taskBatchId") Long taskBatchId,
 | 
			
		||||
                                                             @RequestParam(value = "taskId") Long taskId,
 | 
			
		||||
                                                             @RequestParam(value = "startId") Integer startId,
 | 
			
		||||
                                                             @RequestParam(value = "fromIndex") Integer fromIndex,
 | 
			
		||||
                                                             @RequestParam(value = "size") Integer size);
 | 
			
		||||
    @GetMapping("/log/list")
 | 
			
		||||
    Result<JobInstanceLogPageResult> pageLog(@SpringQueryMap JobInstanceLogQuery query);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,6 @@ import cn.hutool.jwt.RegisteredPayload;
 | 
			
		||||
import com.aizuda.snailjob.common.core.model.Result;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.http.ResponseEntity;
 | 
			
		||||
import top.continew.admin.schedule.constant.JobConstants;
 | 
			
		||||
import top.continew.admin.schedule.model.JobPageResult;
 | 
			
		||||
import top.continew.starter.cache.redisson.util.RedisUtils;
 | 
			
		||||
@@ -74,10 +73,8 @@ public class JobClient {
 | 
			
		||||
     * @param <T>         响应类型
 | 
			
		||||
     * @return 响应信息
 | 
			
		||||
     */
 | 
			
		||||
    public <T> T request(Supplier<ResponseEntity<Result<T>>> apiSupplier) {
 | 
			
		||||
        ResponseEntity<Result<T>> responseEntity = apiSupplier.get();
 | 
			
		||||
        this.checkResponse(responseEntity);
 | 
			
		||||
        Result<T> result = responseEntity.getBody();
 | 
			
		||||
    public <T> T request(Supplier<Result<T>> apiSupplier) {
 | 
			
		||||
        Result<T> result = apiSupplier.get();
 | 
			
		||||
        if (!STATUS_SUCCESS.equals(result.getStatus())) {
 | 
			
		||||
            throw new IllegalStateException(result.getMessage());
 | 
			
		||||
        }
 | 
			
		||||
@@ -91,10 +88,8 @@ public class JobClient {
 | 
			
		||||
     * @param <T>         响应类型
 | 
			
		||||
     * @return 分页列表信息
 | 
			
		||||
     */
 | 
			
		||||
    public <T> PageResp<T> requestPage(Supplier<ResponseEntity<JobPageResult<List<T>>>> apiSupplier) {
 | 
			
		||||
        ResponseEntity<JobPageResult<List<T>>> responseEntity = apiSupplier.get();
 | 
			
		||||
        this.checkResponse(responseEntity);
 | 
			
		||||
        JobPageResult<List<T>> result = responseEntity.getBody();
 | 
			
		||||
    public <T> PageResp<T> requestPage(Supplier<JobPageResult<List<T>>> apiSupplier) {
 | 
			
		||||
        JobPageResult<List<T>> result = apiSupplier.get();
 | 
			
		||||
        if (!STATUS_SUCCESS.equals(result.getStatus())) {
 | 
			
		||||
            throw new IllegalStateException(result.getMessage());
 | 
			
		||||
        }
 | 
			
		||||
@@ -143,15 +138,4 @@ public class JobClient {
 | 
			
		||||
        }
 | 
			
		||||
        return JSONUtil.parseObj(result.getData()).getStr("token");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 检查响应
 | 
			
		||||
     *
 | 
			
		||||
     * @param responseEntity 响应信息
 | 
			
		||||
     */
 | 
			
		||||
    private void checkResponse(ResponseEntity<?> responseEntity) {
 | 
			
		||||
        if (!responseEntity.getStatusCode().is2xxSuccessful() || responseEntity.getBody() == null) {
 | 
			
		||||
            throw new IllegalStateException("连接任务调度中心异常");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,42 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.continew.admin.schedule.api;
 | 
			
		||||
 | 
			
		||||
import com.aizuda.snailjob.common.core.model.Result;
 | 
			
		||||
import org.springframework.cloud.openfeign.FeignClient;
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
			
		||||
import top.continew.admin.schedule.config.FeignRequestInterceptor;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 任务组 REST API
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 2025/3/28 22:25
 | 
			
		||||
 */
 | 
			
		||||
@FeignClient(value = "job-group", url = "${snail-job.server.api.url}", path = "/group", configuration = FeignRequestInterceptor.class)
 | 
			
		||||
public interface JobGroupApi {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询分组列表
 | 
			
		||||
     *
 | 
			
		||||
     * @return 响应信息
 | 
			
		||||
     */
 | 
			
		||||
    @GetMapping("/all/group-name/list")
 | 
			
		||||
    Result<List<String>> listGroup();
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,63 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.continew.admin.schedule.config;
 | 
			
		||||
 | 
			
		||||
import feign.Logger;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import top.continew.admin.schedule.api.JobClient;
 | 
			
		||||
import top.continew.starter.core.autoconfigure.project.ProjectProperties;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Feign 配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 2025/3/28 21:17
 | 
			
		||||
 */
 | 
			
		||||
@Configuration
 | 
			
		||||
@RequiredArgsConstructor
 | 
			
		||||
public class FeignConfiguration {
 | 
			
		||||
 | 
			
		||||
    private final ProjectProperties projectProperties;
 | 
			
		||||
 | 
			
		||||
    @Value("${snail-job.server.api.url}")
 | 
			
		||||
    private String baseUrl;
 | 
			
		||||
 | 
			
		||||
    @Value("${snail-job.server.api.username}")
 | 
			
		||||
    private String username;
 | 
			
		||||
 | 
			
		||||
    @Value("${snail-job.server.api.password}")
 | 
			
		||||
    private String password;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 调度客户端
 | 
			
		||||
     */
 | 
			
		||||
    @Bean
 | 
			
		||||
    public JobClient jobClient() {
 | 
			
		||||
        return new JobClient(baseUrl, username, password);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Feign 日志级别
 | 
			
		||||
     */
 | 
			
		||||
    @Bean
 | 
			
		||||
    public Logger.Level feignLoggerLevel() {
 | 
			
		||||
        return projectProperties.isProduction() ? Logger.Level.BASIC : Logger.Level.FULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,47 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.continew.admin.schedule.config;
 | 
			
		||||
 | 
			
		||||
import feign.RequestInterceptor;
 | 
			
		||||
import feign.RequestTemplate;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import top.continew.admin.schedule.api.JobClient;
 | 
			
		||||
import top.continew.admin.schedule.constant.JobConstants;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Feign 请求拦截器
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 2025/3/28 21:17
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
@RequiredArgsConstructor
 | 
			
		||||
public class FeignRequestInterceptor implements RequestInterceptor {
 | 
			
		||||
 | 
			
		||||
    private final JobClient jobClient;
 | 
			
		||||
 | 
			
		||||
    @Value("${snail-job.namespace}")
 | 
			
		||||
    private String namespace;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void apply(RequestTemplate requestTemplate) {
 | 
			
		||||
        requestTemplate.header(JobConstants.NAMESPACE_ID_HEADER, namespace);
 | 
			
		||||
        requestTemplate.header(JobConstants.AUTH_TOKEN_HEADER, jobClient.getToken());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,134 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.continew.admin.schedule.config;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.databind.ObjectMapper;
 | 
			
		||||
import io.netty.channel.ChannelOption;
 | 
			
		||||
import io.netty.handler.timeout.ReadTimeoutHandler;
 | 
			
		||||
import io.netty.handler.timeout.WriteTimeoutHandler;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
 | 
			
		||||
import org.springframework.http.codec.json.Jackson2JsonDecoder;
 | 
			
		||||
import org.springframework.http.codec.json.Jackson2JsonEncoder;
 | 
			
		||||
import org.springframework.web.reactive.function.client.ClientRequest;
 | 
			
		||||
import org.springframework.web.reactive.function.client.ClientResponse;
 | 
			
		||||
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
 | 
			
		||||
import org.springframework.web.reactive.function.client.WebClient;
 | 
			
		||||
import org.springframework.web.reactive.function.client.support.WebClientAdapter;
 | 
			
		||||
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
 | 
			
		||||
import reactor.core.publisher.Mono;
 | 
			
		||||
import reactor.netty.http.client.HttpClient;
 | 
			
		||||
import top.continew.admin.schedule.api.JobApi;
 | 
			
		||||
import top.continew.admin.schedule.api.JobBatchApi;
 | 
			
		||||
import top.continew.admin.schedule.api.JobClient;
 | 
			
		||||
import top.continew.admin.schedule.constant.JobConstants;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * HTTP Exchange 配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author KAI
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 2024/6/25 18:03
 | 
			
		||||
 */
 | 
			
		||||
@Slf4j
 | 
			
		||||
@Configuration
 | 
			
		||||
@RequiredArgsConstructor
 | 
			
		||||
public class HttpExchangeConfiguration {
 | 
			
		||||
 | 
			
		||||
    private final ObjectMapper objectMapper;
 | 
			
		||||
    @Value("${snail-job.namespace}")
 | 
			
		||||
    private String namespace;
 | 
			
		||||
 | 
			
		||||
    @Value("${snail-job.server.api.url}")
 | 
			
		||||
    private String baseUrl;
 | 
			
		||||
 | 
			
		||||
    @Value("${snail-job.server.api.username}")
 | 
			
		||||
    private String username;
 | 
			
		||||
 | 
			
		||||
    @Value("${snail-job.server.api.password}")
 | 
			
		||||
    private String password;
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public JobApi jobApi() {
 | 
			
		||||
        return httpServiceProxyFactory().createClient(JobApi.class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public JobBatchApi jobBatchApi() {
 | 
			
		||||
        return httpServiceProxyFactory().createClient(JobBatchApi.class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public HttpServiceProxyFactory httpServiceProxyFactory() {
 | 
			
		||||
        HttpClient httpClient = HttpClient.create()
 | 
			
		||||
            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000)
 | 
			
		||||
            .doOnConnected(conn -> {
 | 
			
		||||
                conn.addHandlerLast(new ReadTimeoutHandler(10));
 | 
			
		||||
                conn.addHandlerLast(new WriteTimeoutHandler(10));
 | 
			
		||||
            })
 | 
			
		||||
            .wiretap(true);
 | 
			
		||||
 | 
			
		||||
        WebClient webClient = WebClient.builder()
 | 
			
		||||
            .codecs(config -> config.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper)))
 | 
			
		||||
            .codecs(config -> config.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper)))
 | 
			
		||||
            .clientConnector(new ReactorClientHttpConnector(httpClient))
 | 
			
		||||
            .filter(logRequest())
 | 
			
		||||
            .filter(logResponse())
 | 
			
		||||
            .filter((request, next) -> {
 | 
			
		||||
                // 设置请求头
 | 
			
		||||
                ClientRequest filtered = ClientRequest.from(request)
 | 
			
		||||
                    .header(JobConstants.NAMESPACE_ID_HEADER, namespace)
 | 
			
		||||
                    .header(JobConstants.AUTH_TOKEN_HEADER, jobClient().getToken())
 | 
			
		||||
                    .build();
 | 
			
		||||
                return next.exchange(filtered);
 | 
			
		||||
            })
 | 
			
		||||
            .baseUrl(baseUrl)
 | 
			
		||||
            .build();
 | 
			
		||||
        return HttpServiceProxyFactory.builderFor(WebClientAdapter.create(webClient)).build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public JobClient jobClient() {
 | 
			
		||||
        return new JobClient(baseUrl, username, password);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 打印请求日志
 | 
			
		||||
     */
 | 
			
		||||
    private ExchangeFilterFunction logRequest() {
 | 
			
		||||
        return ExchangeFilterFunction.ofRequestProcessor(request -> {
 | 
			
		||||
            log.info("---> {} {}", request.method(), request.url());
 | 
			
		||||
            return Mono.just(request);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 打印响应日志
 | 
			
		||||
     */
 | 
			
		||||
    private ExchangeFilterFunction logResponse() {
 | 
			
		||||
        return ExchangeFilterFunction.ofResponseProcessor(response -> response.bodyToMono(String.class)
 | 
			
		||||
            .flatMap(body -> {
 | 
			
		||||
                log.info("<--- {}", response.statusCode());
 | 
			
		||||
                log.info(body);
 | 
			
		||||
                return Mono.just(ClientResponse.from(response).body(body).build());
 | 
			
		||||
            }));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -17,14 +17,12 @@
 | 
			
		||||
package top.continew.admin.schedule.model.query;
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import jakarta.validation.constraints.Min;
 | 
			
		||||
import jakarta.validation.constraints.Size;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.hibernate.validator.constraints.Range;
 | 
			
		||||
import top.continew.admin.schedule.enums.JobExecuteStatusEnum;
 | 
			
		||||
import top.continew.starter.core.validation.constraints.EnumValue;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -35,7 +33,7 @@ import java.time.LocalDateTime;
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Schema(description = "任务日志查询条件")
 | 
			
		||||
public class JobLogQuery implements Serializable {
 | 
			
		||||
public class JobLogQuery extends JobPageQuery {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
@@ -62,7 +60,8 @@ public class JobLogQuery implements Serializable {
 | 
			
		||||
     * 任务批次状态
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "任务批次状态", example = "1")
 | 
			
		||||
    private JobExecuteStatusEnum taskBatchStatus;
 | 
			
		||||
    @EnumValue(value = JobExecuteStatusEnum.class, message = "任务批次状态无效")
 | 
			
		||||
    private Integer taskBatchStatus;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建时间
 | 
			
		||||
@@ -70,18 +69,4 @@ public class JobLogQuery implements Serializable {
 | 
			
		||||
    @Schema(description = "创建时间", example = "2023-08-08 00:00:00,2023-08-08 23:59:59")
 | 
			
		||||
    @Size(max = 2, message = "创建时间必须是一个范围")
 | 
			
		||||
    private LocalDateTime[] datetimeRange;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 页码
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "页码", example = "1")
 | 
			
		||||
    @Min(value = 1, message = "页码最小值为 {value}")
 | 
			
		||||
    private Integer page = 1;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 每页条数
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "每页条数", example = "10")
 | 
			
		||||
    @Range(min = 1, max = 1000, message = "每页条数(取值范围 {min}-{max})")
 | 
			
		||||
    private Integer size = 10;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package top.continew.admin.schedule.model.query;
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import jakarta.validation.constraints.Min;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.hibernate.validator.constraints.Range;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 任务分页查询条件
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 2025/3/28 21:55
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class JobPageQuery implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 页码
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "页码", example = "1")
 | 
			
		||||
    @Min(value = 1, message = "页码最小值为 {value}")
 | 
			
		||||
    private Integer page = 1;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 每页条数
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "每页条数", example = "10")
 | 
			
		||||
    @Range(min = 1, max = 1000, message = "每页条数(取值范围 {min}-{max})")
 | 
			
		||||
    private Integer size = 10;
 | 
			
		||||
}
 | 
			
		||||
@@ -17,13 +17,11 @@
 | 
			
		||||
package top.continew.admin.schedule.model.query;
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import jakarta.validation.constraints.Min;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.hibernate.validator.constraints.Range;
 | 
			
		||||
import top.continew.admin.schedule.enums.JobStatusEnum;
 | 
			
		||||
import top.continew.starter.core.validation.constraints.EnumValue;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 任务查询条件
 | 
			
		||||
@@ -33,7 +31,7 @@ import java.io.Serializable;
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Schema(description = "任务查询条件")
 | 
			
		||||
public class JobQuery implements Serializable {
 | 
			
		||||
public class JobQuery extends JobPageQuery {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
@@ -54,19 +52,6 @@ public class JobQuery implements Serializable {
 | 
			
		||||
     * 任务状态
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "任务状态", example = "1")
 | 
			
		||||
    private JobStatusEnum jobStatus;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 页码
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "页码", example = "1")
 | 
			
		||||
    @Min(value = 1, message = "页码最小值为 {value}")
 | 
			
		||||
    private Integer page = 1;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 每页条数
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "每页条数", example = "10")
 | 
			
		||||
    @Range(min = 1, max = 1000, message = "每页条数(取值范围 {min}-{max})")
 | 
			
		||||
    private Integer size = 10;
 | 
			
		||||
    @EnumValue(value = JobStatusEnum.class, message = "任务状态无效")
 | 
			
		||||
    private Integer jobStatus;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -80,18 +80,18 @@ public class JobResp implements Serializable {
 | 
			
		||||
    @Schema(description = " 执行器类型", example = "1")
 | 
			
		||||
    private Integer executorType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 任务类型
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "任务类型", example = "1")
 | 
			
		||||
    private JobTaskTypeEnum taskType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 执行器名称
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "执行器名称", example = "test")
 | 
			
		||||
    private String executorInfo;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 任务类型
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "任务类型", example = "1")
 | 
			
		||||
    private JobTaskTypeEnum taskType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 任务参数
 | 
			
		||||
     */
 | 
			
		||||
 
 | 
			
		||||
@@ -16,8 +16,6 @@
 | 
			
		||||
 | 
			
		||||
package top.continew.admin.schedule.service.impl;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.date.DatePattern;
 | 
			
		||||
import cn.hutool.core.date.DateUtil;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import top.continew.admin.schedule.api.JobBatchApi;
 | 
			
		||||
@@ -31,9 +29,7 @@ import top.continew.admin.schedule.model.resp.JobLogResp;
 | 
			
		||||
import top.continew.admin.schedule.service.JobLogService;
 | 
			
		||||
import top.continew.starter.extension.crud.model.resp.PageResp;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 任务日志业务实现
 | 
			
		||||
@@ -51,12 +47,7 @@ public class JobLogServiceImpl implements JobLogService {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public PageResp<JobLogResp> page(JobLogQuery query) {
 | 
			
		||||
        LocalDateTime[] datetimeRange = query.getDatetimeRange();
 | 
			
		||||
        return jobClient.requestPage(() -> jobBatchApi.page(query.getJobId(), query.getJobName(), query
 | 
			
		||||
            .getGroupName(), query.getTaskBatchStatus() != null
 | 
			
		||||
                ? query.getTaskBatchStatus().getValue()
 | 
			
		||||
                : null, new String[] {DateUtil.format(datetimeRange[0], DatePattern.UTC_SIMPLE_PATTERN), DateUtil
 | 
			
		||||
                    .format(datetimeRange[1], DatePattern.UTC_SIMPLE_PATTERN)}, query.getPage(), query.getSize()));
 | 
			
		||||
        return jobClient.requestPage(() -> jobBatchApi.page(query));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -71,13 +62,11 @@ public class JobLogServiceImpl implements JobLogService {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<JobInstanceResp> listInstance(JobInstanceQuery query) {
 | 
			
		||||
        return jobClient.requestPage(() -> jobBatchApi.pageTask(query.getJobId(), query.getTaskBatchId(), 1, 100))
 | 
			
		||||
            .getList();
 | 
			
		||||
        return jobClient.requestPage(() -> jobBatchApi.pageTask(query)).getList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public JobInstanceLogPageResult pageInstanceLog(JobInstanceLogQuery query) {
 | 
			
		||||
        return Objects.requireNonNull(jobBatchApi.pageLog(query.getJobId(), query.getTaskBatchId(), query
 | 
			
		||||
            .getTaskId(), query.getStartId(), query.getFromIndex(), query.getSize()).getBody()).getData();
 | 
			
		||||
        return jobClient.request(() -> jobBatchApi.pageLog(query));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ import lombok.RequiredArgsConstructor;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import top.continew.admin.schedule.api.JobApi;
 | 
			
		||||
import top.continew.admin.schedule.api.JobClient;
 | 
			
		||||
import top.continew.admin.schedule.api.JobGroupApi;
 | 
			
		||||
import top.continew.admin.schedule.model.query.JobQuery;
 | 
			
		||||
import top.continew.admin.schedule.model.req.JobReq;
 | 
			
		||||
import top.continew.admin.schedule.model.req.JobStatusReq;
 | 
			
		||||
@@ -44,11 +45,11 @@ public class JobServiceImpl implements JobService {
 | 
			
		||||
 | 
			
		||||
    private final JobClient jobClient;
 | 
			
		||||
    private final JobApi jobApi;
 | 
			
		||||
    private final JobGroupApi jobGroupApi;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public PageResp<JobResp> page(JobQuery query) {
 | 
			
		||||
        return jobClient.requestPage(() -> jobApi.page(query.getGroupName(), query.getJobName(), query
 | 
			
		||||
            .getJobStatus() != null ? query.getJobStatus().getValue() : null, query.getPage(), query.getSize()));
 | 
			
		||||
        return jobClient.requestPage(() -> jobApi.page(query));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -80,6 +81,6 @@ public class JobServiceImpl implements JobService {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<String> listGroup() {
 | 
			
		||||
        return jobClient.request(jobApi::listGroup);
 | 
			
		||||
        return jobClient.request(jobGroupApi::listGroup);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user