mirror of
https://github.com/continew-org/continew-admin.git
synced 2025-09-12 06:57:13 +08:00
refactor(schedule): 重构任务调度模块,使用 OpenFeign 替代 WebClient
This commit is contained in:
@@ -25,15 +25,10 @@
|
||||
<artifactId>snail-job-client-job-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring WebFlux(异步非阻塞 Web 框架) -->
|
||||
<!-- OpenFeign(一种基于 Spring Cloud 的声明式 REST 客户端,它简化了与 HTTP 服务交互的过程) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webflux</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.projectreactor.netty</groupId>
|
||||
<artifactId>reactor-netty-http</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@@ -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