feat(1.5.0-beta1): OpenApi支持重试任务的查询、触发、状态更新

This commit is contained in:
xiaochaihu 2025-03-30 18:16:49 +08:00 committed by opensnail
parent 03a5b73937
commit 5a5fd8e6ff
37 changed files with 594 additions and 46 deletions

View File

@ -1,4 +1,4 @@
package com.aizuda.snailjob.client.job.core.handler; package com.aizuda.snailjob.client.common.rpc.openapi;
import cn.hutool.core.lang.Pair; import cn.hutool.core.lang.Pair;
import com.aizuda.snailjob.client.common.exception.SnailJobClientException; import com.aizuda.snailjob.client.common.exception.SnailJobClientException;
@ -12,6 +12,7 @@ public abstract class AbstractRequestHandler<R> implements RequestHandler<R> {
/** /**
* 具体调用 * 具体调用
*
* @return * @return
*/ */
@Override @Override
@ -27,9 +28,11 @@ public abstract class AbstractRequestHandler<R> implements RequestHandler<R> {
} }
} }
protected abstract void afterExecute(R r); protected void afterExecute(R r) {
}
protected abstract void beforeExecute(); protected void beforeExecute() {
}
protected abstract R doExecute(); protected abstract R doExecute();

View File

@ -0,0 +1,7 @@
package com.aizuda.snailjob.client.common.rpc.openapi;
public interface RequestHandler<R> {
R execute();
}

View File

@ -1,4 +1,4 @@
package com.aizuda.snailjob.client.job.core.util; package com.aizuda.snailjob.client.common.util;
import cn.hutool.core.lang.Pair; import cn.hutool.core.lang.Pair;
import com.aizuda.snailjob.client.common.exception.SnailJobClientException; import com.aizuda.snailjob.client.common.exception.SnailJobClientException;

View File

@ -0,0 +1,18 @@
package com.aizuda.snailjob.client.job.core.handler;
import com.aizuda.snailjob.client.common.rpc.client.RequestBuilder;
import com.aizuda.snailjob.client.common.rpc.openapi.AbstractRequestHandler;
import com.aizuda.snailjob.client.job.core.openapi.JobOpenApiClient;
import com.aizuda.snailjob.common.core.model.SnailJobRpcResult;
/**
* @author opensnail
* @date 2024-09-29 20:40:10
* @since sj_1.1.0
*/
public abstract class AbstractJobRequestHandler<R> extends AbstractRequestHandler<R> {
protected JobOpenApiClient client = RequestBuilder.<JobOpenApiClient, SnailJobRpcResult>newBuilder()
.client(JobOpenApiClient.class)
.async(false)
.build();
}

View File

@ -21,7 +21,7 @@ import static com.aizuda.snailjob.client.job.core.enums.TriggerTypeEnum.*;
* @date 2024-10-19 22:34:38 * @date 2024-10-19 22:34:38
* @since sj_1.2.0 * @since sj_1.2.0
*/ */
public abstract class AbstractParamsHandler<H, R> extends AbstractRequestHandler<R> { public abstract class AbstractParamsHandler<H, R> extends AbstractJobRequestHandler<R> {
protected static final String SHARD_NUM = "shardNum"; protected static final String SHARD_NUM = "shardNum";
@Getter @Getter
private final RequestAddOrUpdateJobDTO reqDTO; private final RequestAddOrUpdateJobDTO reqDTO;

View File

@ -10,7 +10,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
public abstract class AbstractTriggerHandler<H, R> extends AbstractRequestHandler<R> { public abstract class AbstractTriggerHandler<H, R> extends AbstractJobRequestHandler<R> {
@Getter @Getter
private final JobTriggerDTO reqDTO; private final JobTriggerDTO reqDTO;
@Setter @Setter

View File

@ -1,16 +0,0 @@
package com.aizuda.snailjob.client.job.core.handler;
import com.aizuda.snailjob.client.common.rpc.client.RequestBuilder;
import com.aizuda.snailjob.client.job.core.openapi.OpenApiClient;
import com.aizuda.snailjob.common.core.model.SnailJobRpcResult;
public interface RequestHandler<R> {
OpenApiClient client = RequestBuilder.<OpenApiClient, SnailJobRpcResult>newBuilder()
.client(OpenApiClient.class)
.async(false)
.build();
R execute();
}

View File

@ -4,7 +4,7 @@ import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Pair; import cn.hutool.core.lang.Pair;
import com.aizuda.snailjob.client.common.exception.SnailJobClientException; import com.aizuda.snailjob.client.common.exception.SnailJobClientException;
import com.aizuda.snailjob.client.job.core.handler.AbstractParamsHandler; import com.aizuda.snailjob.client.job.core.handler.AbstractParamsHandler;
import com.aizuda.snailjob.client.job.core.util.ValidatorUtils; import com.aizuda.snailjob.client.common.util.ValidatorUtils;
import com.aizuda.snailjob.common.core.enums.JobTaskTypeEnum; import com.aizuda.snailjob.common.core.enums.JobTaskTypeEnum;
import com.aizuda.snailjob.common.core.enums.StatusEnum; import com.aizuda.snailjob.common.core.enums.StatusEnum;
import com.aizuda.snailjob.common.core.model.Result; import com.aizuda.snailjob.common.core.model.Result;

View File

@ -3,7 +3,7 @@ package com.aizuda.snailjob.client.job.core.handler.delete;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Pair; import cn.hutool.core.lang.Pair;
import com.aizuda.snailjob.client.common.exception.SnailJobClientException; import com.aizuda.snailjob.client.common.exception.SnailJobClientException;
import com.aizuda.snailjob.client.job.core.handler.AbstractRequestHandler; import com.aizuda.snailjob.client.job.core.handler.AbstractJobRequestHandler;
import com.aizuda.snailjob.common.core.enums.StatusEnum; import com.aizuda.snailjob.common.core.enums.StatusEnum;
import com.aizuda.snailjob.common.core.model.Result; import com.aizuda.snailjob.common.core.model.Result;
@ -16,7 +16,7 @@ import java.util.Set;
* @Date2024/11/21 22:38 * @Date2024/11/21 22:38
* @FilenameDeleteJobHandler * @FilenameDeleteJobHandler
*/ */
public class DeleteJobHandler extends AbstractRequestHandler<Boolean> { public class DeleteJobHandler extends AbstractJobRequestHandler<Boolean> {
private final Set<Long> toDeleteIds; private final Set<Long> toDeleteIds;
public DeleteJobHandler(Set<Long> toDeleteIds) { public DeleteJobHandler(Set<Long> toDeleteIds) {

View File

@ -3,7 +3,7 @@ package com.aizuda.snailjob.client.job.core.handler.delete;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Pair; import cn.hutool.core.lang.Pair;
import com.aizuda.snailjob.client.common.exception.SnailJobClientException; import com.aizuda.snailjob.client.common.exception.SnailJobClientException;
import com.aizuda.snailjob.client.job.core.handler.AbstractRequestHandler; import com.aizuda.snailjob.client.job.core.handler.AbstractJobRequestHandler;
import com.aizuda.snailjob.common.core.enums.StatusEnum; import com.aizuda.snailjob.common.core.enums.StatusEnum;
import com.aizuda.snailjob.common.core.model.Result; import com.aizuda.snailjob.common.core.model.Result;
@ -16,7 +16,7 @@ import java.util.Set;
* @Date2024/11/21 22:42 * @Date2024/11/21 22:42
* @FilenameDeleteWorkflowHandler * @FilenameDeleteWorkflowHandler
*/ */
public class DeleteWorkflowHandler extends AbstractRequestHandler<Boolean> { public class DeleteWorkflowHandler extends AbstractJobRequestHandler<Boolean> {
private final Set<Long> toDeleteIds; private final Set<Long> toDeleteIds;
public DeleteWorkflowHandler(Set<Long> toDeleteIds) { public DeleteWorkflowHandler(Set<Long> toDeleteIds) {

View File

@ -5,14 +5,14 @@ import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Pair; import cn.hutool.core.lang.Pair;
import com.aizuda.snailjob.client.common.exception.SnailJobClientException; import com.aizuda.snailjob.client.common.exception.SnailJobClientException;
import com.aizuda.snailjob.client.job.core.dto.JobResponseVO; import com.aizuda.snailjob.client.job.core.dto.JobResponseVO;
import com.aizuda.snailjob.client.job.core.handler.AbstractRequestHandler; import com.aizuda.snailjob.client.job.core.handler.AbstractJobRequestHandler;
import com.aizuda.snailjob.common.core.enums.StatusEnum; import com.aizuda.snailjob.common.core.enums.StatusEnum;
import com.aizuda.snailjob.common.core.model.Result; import com.aizuda.snailjob.common.core.model.Result;
import com.aizuda.snailjob.common.core.util.JsonUtil; import com.aizuda.snailjob.common.core.util.JsonUtil;
import java.util.Objects; import java.util.Objects;
public class RequestQueryHandler extends AbstractRequestHandler<JobResponseVO> { public class RequestQueryHandler extends AbstractJobRequestHandler<JobResponseVO> {
private final Long queryJobId; private final Long queryJobId;
public RequestQueryHandler(Long queryJobId) { public RequestQueryHandler(Long queryJobId) {

View File

@ -5,7 +5,7 @@ import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Pair; import cn.hutool.core.lang.Pair;
import com.aizuda.snailjob.client.common.exception.SnailJobClientException; import com.aizuda.snailjob.client.common.exception.SnailJobClientException;
import com.aizuda.snailjob.client.job.core.dto.JobBatchResponseVO; import com.aizuda.snailjob.client.job.core.dto.JobBatchResponseVO;
import com.aizuda.snailjob.client.job.core.handler.AbstractRequestHandler; import com.aizuda.snailjob.client.job.core.handler.AbstractJobRequestHandler;
import com.aizuda.snailjob.common.core.enums.StatusEnum; import com.aizuda.snailjob.common.core.enums.StatusEnum;
import com.aizuda.snailjob.common.core.model.Result; import com.aizuda.snailjob.common.core.model.Result;
import com.aizuda.snailjob.common.core.util.JsonUtil; import com.aizuda.snailjob.common.core.util.JsonUtil;
@ -15,7 +15,7 @@ import java.util.Objects;
/** /**
* @since 1.5.0 * @since 1.5.0
*/ */
public class RequestQueryJobBatchHandler extends AbstractRequestHandler<JobBatchResponseVO> { public class RequestQueryJobBatchHandler extends AbstractJobRequestHandler<JobBatchResponseVO> {
private final Long queryJobBatchId; private final Long queryJobBatchId;
public RequestQueryJobBatchHandler(Long queryJobBatchId) { public RequestQueryJobBatchHandler(Long queryJobBatchId) {

View File

@ -5,7 +5,7 @@ import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Pair; import cn.hutool.core.lang.Pair;
import com.aizuda.snailjob.client.common.exception.SnailJobClientException; import com.aizuda.snailjob.client.common.exception.SnailJobClientException;
import com.aizuda.snailjob.client.job.core.dto.WorkflowDetailResponseVO; import com.aizuda.snailjob.client.job.core.dto.WorkflowDetailResponseVO;
import com.aizuda.snailjob.client.job.core.handler.AbstractRequestHandler; import com.aizuda.snailjob.client.job.core.handler.AbstractJobRequestHandler;
import com.aizuda.snailjob.common.core.enums.StatusEnum; import com.aizuda.snailjob.common.core.enums.StatusEnum;
import com.aizuda.snailjob.common.core.model.Result; import com.aizuda.snailjob.common.core.model.Result;
import com.aizuda.snailjob.common.core.util.JsonUtil; import com.aizuda.snailjob.common.core.util.JsonUtil;
@ -15,7 +15,7 @@ import java.util.Objects;
/** /**
* @since 1.5.0 * @since 1.5.0
*/ */
public class RequestQueryWorkflowBatchHandler extends AbstractRequestHandler<WorkflowDetailResponseVO> { public class RequestQueryWorkflowBatchHandler extends AbstractJobRequestHandler<WorkflowDetailResponseVO> {
private final Long workflowBatchId; private final Long workflowBatchId;
public RequestQueryWorkflowBatchHandler(Long workflowBatchId) { public RequestQueryWorkflowBatchHandler(Long workflowBatchId) {

View File

@ -5,11 +5,10 @@ import cn.hutool.core.lang.Pair;
import com.aizuda.snailjob.client.common.exception.SnailJobClientException; import com.aizuda.snailjob.client.common.exception.SnailJobClientException;
import com.aizuda.snailjob.client.job.core.enums.TriggerTypeEnum; import com.aizuda.snailjob.client.job.core.enums.TriggerTypeEnum;
import com.aizuda.snailjob.client.job.core.handler.AbstractParamsHandler; import com.aizuda.snailjob.client.job.core.handler.AbstractParamsHandler;
import com.aizuda.snailjob.client.job.core.util.ValidatorUtils; import com.aizuda.snailjob.client.common.util.ValidatorUtils;
import com.aizuda.snailjob.common.core.enums.JobTaskTypeEnum; import com.aizuda.snailjob.common.core.enums.JobTaskTypeEnum;
import com.aizuda.snailjob.common.core.enums.StatusEnum; import com.aizuda.snailjob.common.core.enums.StatusEnum;
import com.aizuda.snailjob.common.core.model.Result; import com.aizuda.snailjob.common.core.model.Result;
import com.aizuda.snailjob.common.core.util.JsonUtil;
public abstract class UpdateHandler<H> extends AbstractParamsHandler<H, Boolean> { public abstract class UpdateHandler<H> extends AbstractParamsHandler<H, Boolean> {

View File

@ -4,13 +4,13 @@ import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Pair; import cn.hutool.core.lang.Pair;
import com.aizuda.snailjob.client.common.exception.SnailJobClientException; import com.aizuda.snailjob.client.common.exception.SnailJobClientException;
import com.aizuda.snailjob.client.job.core.dto.RequestUpdateStatusDTO; import com.aizuda.snailjob.client.job.core.dto.RequestUpdateStatusDTO;
import com.aizuda.snailjob.client.job.core.handler.AbstractRequestHandler; import com.aizuda.snailjob.client.job.core.handler.AbstractJobRequestHandler;
import com.aizuda.snailjob.client.job.core.util.ValidatorUtils; import com.aizuda.snailjob.client.common.util.ValidatorUtils;
import com.aizuda.snailjob.common.core.enums.StatusEnum; import com.aizuda.snailjob.common.core.enums.StatusEnum;
import com.aizuda.snailjob.common.core.model.Result; import com.aizuda.snailjob.common.core.model.Result;
public class UpdateJobStatusHandler extends AbstractRequestHandler<Boolean> { public class UpdateJobStatusHandler extends AbstractJobRequestHandler<Boolean> {
private final RequestUpdateStatusDTO statusDTO; private final RequestUpdateStatusDTO statusDTO;
public UpdateJobStatusHandler(Long id) { public UpdateJobStatusHandler(Long id) {

View File

@ -4,13 +4,13 @@ import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Pair; import cn.hutool.core.lang.Pair;
import com.aizuda.snailjob.client.common.exception.SnailJobClientException; import com.aizuda.snailjob.client.common.exception.SnailJobClientException;
import com.aizuda.snailjob.client.job.core.dto.RequestUpdateStatusDTO; import com.aizuda.snailjob.client.job.core.dto.RequestUpdateStatusDTO;
import com.aizuda.snailjob.client.job.core.handler.AbstractRequestHandler; import com.aizuda.snailjob.client.job.core.handler.AbstractJobRequestHandler;
import com.aizuda.snailjob.client.job.core.util.ValidatorUtils; import com.aizuda.snailjob.client.common.util.ValidatorUtils;
import com.aizuda.snailjob.common.core.enums.StatusEnum; import com.aizuda.snailjob.common.core.enums.StatusEnum;
import com.aizuda.snailjob.common.core.model.Result; import com.aizuda.snailjob.common.core.model.Result;
public class UpdateWorkflowStatusHandler extends AbstractRequestHandler<Boolean> { public class UpdateWorkflowStatusHandler extends AbstractJobRequestHandler<Boolean> {
private final RequestUpdateStatusDTO statusDTO; private final RequestUpdateStatusDTO statusDTO;
public UpdateWorkflowStatusHandler(Long id) { public UpdateWorkflowStatusHandler(Long id) {

View File

@ -9,7 +9,7 @@ import com.aizuda.snailjob.common.core.model.Result;
import java.util.Set; import java.util.Set;
public interface OpenApiClient { public interface JobOpenApiClient {
@Mapping(method = RequestMethod.POST, path = "/api/job/add") @Mapping(method = RequestMethod.POST, path = "/api/job/add")
Result<Object> addJob(RequestAddOrUpdateJobDTO requestAddOrUpdateJobDTO); Result<Object> addJob(RequestAddOrUpdateJobDTO requestAddOrUpdateJobDTO);

View File

@ -0,0 +1,10 @@
package com.aizuda.snailjob.client.core.dto;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
public class RequestTriggerRetryDTO {
@NotNull(message = "id 不能为空")
private Long id;
}

View File

@ -0,0 +1,13 @@
package com.aizuda.snailjob.client.core.dto;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
public class RequestUpdateRetryStatusDTO {
@NotNull(message = "id 不能为空")
private Long id;
@NotNull(message = "retryStatus 不能为空")
private Integer retryStatus;
}

View File

@ -0,0 +1,43 @@
package com.aizuda.snailjob.client.core.dto;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class RetryDTO {
private Long id;
private String namespaceId;
private String groupName;
private String sceneName;
private String idempotentId;
private String bizNo;
private String argsStr;
private String extAttrs;
private String executorName;
/**
* 下次触发时间
*/
private LocalDateTime nextTriggerAt;
private Integer retryCount;
private Integer retryStatus;
private Integer taskType;
private Long parentId;
private Integer bucketIndex;
private Long deleted;
}

View File

@ -0,0 +1,13 @@
package com.aizuda.snailjob.client.core.handler;
import com.aizuda.snailjob.client.common.rpc.client.RequestBuilder;
import com.aizuda.snailjob.client.common.rpc.openapi.AbstractRequestHandler;
import com.aizuda.snailjob.client.core.openapi.RetryOpenApiClient;
import com.aizuda.snailjob.common.core.model.SnailJobRpcResult;
public abstract class AbstractRetryRequestHandler<T> extends AbstractRequestHandler<T> {
RetryOpenApiClient client = RequestBuilder.<RetryOpenApiClient, SnailJobRpcResult>newBuilder()
.client(RetryOpenApiClient.class)
.async(false)
.build();
}

View File

@ -0,0 +1,35 @@
package com.aizuda.snailjob.client.core.handler;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Pair;
import com.aizuda.snailjob.client.common.exception.SnailJobClientException;
import com.aizuda.snailjob.client.core.dto.RetryDTO;
import com.aizuda.snailjob.common.core.enums.StatusEnum;
import com.aizuda.snailjob.common.core.model.Result;
import com.aizuda.snailjob.common.core.util.JsonUtil;
import java.util.Objects;
public class QueryRetryHandler extends AbstractRetryRequestHandler<RetryDTO> {
private final Long retryId;
public QueryRetryHandler(Long retryId) {
this.retryId = retryId;
}
@Override
protected RetryDTO doExecute() {
Result<Object> result = client.queryRetryTask(retryId);
Assert.isTrue(StatusEnum.YES.getStatus() == result.getStatus(),
() -> new SnailJobClientException(result.getMessage()));
Object data = result.getData();
Assert.isTrue(Objects.nonNull(data), () -> new SnailJobClientException("获取[{}]任务详情失败", retryId));
return JsonUtil.parseObject(JsonUtil.toJsonString(data), RetryDTO.class);
}
@Override
protected Pair<Boolean, String> checkRequest() {
return Pair.of(retryId != null && retryId > 0, "retryId不能为null并且必须大于0");
}
}

View File

@ -0,0 +1,32 @@
package com.aizuda.snailjob.client.core.handler;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Pair;
import com.aizuda.snailjob.client.common.exception.SnailJobClientException;
import com.aizuda.snailjob.client.common.util.ValidatorUtils;
import com.aizuda.snailjob.client.core.dto.RequestTriggerRetryDTO;
import com.aizuda.snailjob.common.core.enums.StatusEnum;
import com.aizuda.snailjob.common.core.model.Result;
public class TriggerRetryHandler extends AbstractRetryRequestHandler<Boolean> {
private final RequestTriggerRetryDTO triggerRetryDTO;
public TriggerRetryHandler(Long retryId) {
this.triggerRetryDTO = new RequestTriggerRetryDTO();
triggerRetryDTO.setId(retryId);
}
@Override
protected Boolean doExecute() {
Result<Object> result = client.triggerRetryTask(triggerRetryDTO);
Assert.isTrue(StatusEnum.YES.getStatus() == result.getStatus(),
() -> new SnailJobClientException(result.getMessage()));
return (Boolean) result.getData();
}
@Override
protected Pair<Boolean, String> checkRequest() {
return ValidatorUtils.validateEntity(triggerRetryDTO);
}
}

View File

@ -0,0 +1,38 @@
package com.aizuda.snailjob.client.core.handler;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Pair;
import com.aizuda.snailjob.client.common.exception.SnailJobClientException;
import com.aizuda.snailjob.client.common.util.ValidatorUtils;
import com.aizuda.snailjob.client.core.dto.RequestUpdateRetryStatusDTO;
import com.aizuda.snailjob.common.core.enums.RetryStatusEnum;
import com.aizuda.snailjob.common.core.enums.StatusEnum;
import com.aizuda.snailjob.common.core.model.Result;
public class UpdateRetryStatusHandler extends AbstractRetryRequestHandler<Boolean> {
private final RequestUpdateRetryStatusDTO updateRetryStatusDTO;
public UpdateRetryStatusHandler(Long retryId) {
this.updateRetryStatusDTO = new RequestUpdateRetryStatusDTO();
updateRetryStatusDTO.setId(retryId);
}
public UpdateRetryStatusHandler setRetryStatus(RetryStatusEnum retryStatusEnum) {
updateRetryStatusDTO.setRetryStatus(retryStatusEnum.getStatus());
return this;
}
@Override
protected Boolean doExecute() {
Result<Object> result = client.updateRetryTaskStatus(updateRetryStatusDTO);
Assert.isTrue(StatusEnum.YES.getStatus() == result.getStatus(),
() -> new SnailJobClientException(result.getMessage()));
return (Boolean) result.getData();
}
@Override
protected Pair<Boolean, String> checkRequest() {
return ValidatorUtils.validateEntity(updateRetryStatusDTO);
}
}

View File

@ -0,0 +1,18 @@
package com.aizuda.snailjob.client.core.openapi;
import com.aizuda.snailjob.client.common.annotation.Mapping;
import com.aizuda.snailjob.client.common.rpc.client.RequestMethod;
import com.aizuda.snailjob.client.core.dto.RequestTriggerRetryDTO;
import com.aizuda.snailjob.client.core.dto.RequestUpdateRetryStatusDTO;
import com.aizuda.snailjob.common.core.model.Result;
public interface RetryOpenApiClient {
@Mapping(method = RequestMethod.POST, path = "/api/retry/query")
Result<Object> queryRetryTask(Long retryId);
@Mapping(method = RequestMethod.POST, path = "/api/retry/triggerRetry")
Result<Object> triggerRetryTask(RequestTriggerRetryDTO triggerRetryDTO);
@Mapping(method = RequestMethod.POST, path = "/api/retry/updateRetryStatus")
Result<Object> updateRetryTaskStatus(RequestUpdateRetryStatusDTO statusDTO);
}

View File

@ -0,0 +1,20 @@
package com.aizuda.snailjob.client.core.openapi;
import com.aizuda.snailjob.client.core.handler.QueryRetryHandler;
import com.aizuda.snailjob.client.core.handler.TriggerRetryHandler;
import com.aizuda.snailjob.client.core.handler.UpdateRetryStatusHandler;
public class SnailRetryOpenApi {
public static QueryRetryHandler queryTask(Long retryId) {
return new QueryRetryHandler(retryId);
}
public static UpdateRetryStatusHandler updateTaskStatus(Long retryId) {
return new UpdateRetryStatusHandler(retryId);
}
public static TriggerRetryHandler triggerTask(Long retryId) {
return new TriggerRetryHandler(retryId);
}
}

View File

@ -167,6 +167,12 @@ public interface SystemConstants {
String OPENAPI_DELETE_WORKFLOW = "/api/job/deleteWorkFlow"; String OPENAPI_DELETE_WORKFLOW = "/api/job/deleteWorkFlow";
String OPENAPI_ADD_RETRY = "/api/retry/query";
String OPENAPI_UPDATE_RETRY_STATUS = "/api/retry/updateRetryStatus";
String OPENAPI_TRIGGER_RETRY = "/api/retry/triggerRetry";
} }
String LOGO = """ String LOGO = """

View File

@ -0,0 +1,29 @@
package com.aizuda.snailjob.server.common.convert;
import com.aizuda.snailjob.server.common.util.DateUtils;
import com.aizuda.snailjob.server.common.vo.RetryResponseVO;
import com.aizuda.snailjob.template.datasource.persistence.po.Retry;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.time.LocalDateTime;
import java.util.Objects;
@Mapper
public interface RetryResponseVOConverter {
RetryResponseVOConverter INSTANCE = Mappers.getMapper(RetryResponseVOConverter.class);
@Mappings({
@Mapping(target = "nextTriggerAt", expression = "java(RetryResponseVOConverter.toLocalDateTime(retry.getNextTriggerAt()))"),
})
RetryResponseVO convert(Retry retry);
static LocalDateTime toLocalDateTime(Long nextTriggerAt) {
if (Objects.isNull(nextTriggerAt) || nextTriggerAt == 0) {
return null;
}
return DateUtils.toLocalDateTime(nextTriggerAt);
}
}

View File

@ -0,0 +1,10 @@
package com.aizuda.snailjob.server.common.vo;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
public class RequestTriggerRetryVO {
@NotNull(message = "id 不能为空")
private Long id;
}

View File

@ -0,0 +1,13 @@
package com.aizuda.snailjob.server.common.vo;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
public class RequestUpdateRetryStatusVO {
@NotNull(message = "id 不能为空")
private Long id;
@NotNull(message = "retryStatus 不能为空")
private Integer retryStatus;
}

View File

@ -0,0 +1,43 @@
package com.aizuda.snailjob.server.common.vo;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class RetryResponseVO {
private Long id;
private String namespaceId;
private String groupName;
private String sceneName;
private String idempotentId;
private String bizNo;
private String argsStr;
private String extAttrs;
private String executorName;
/**
* 下次触发时间
*/
private LocalDateTime nextTriggerAt;
private Integer retryCount;
private Integer retryStatus;
private Integer taskType;
private Long parentId;
private Integer bucketIndex;
private Long deleted;
}

View File

@ -1,10 +1,9 @@
package com.aizuda.snailjob.server.web.service.convert; package com.aizuda.snailjob.server.retry.task.convert;
import com.aizuda.snailjob.server.retry.task.dto.RetryTaskPrepareDTO; import com.aizuda.snailjob.server.retry.task.dto.RetryTaskPrepareDTO;
import com.aizuda.snailjob.server.retry.task.dto.TaskStopJobDTO; import com.aizuda.snailjob.server.retry.task.dto.TaskStopJobDTO;
import com.aizuda.snailjob.template.datasource.persistence.po.Retry; import com.aizuda.snailjob.template.datasource.persistence.po.Retry;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
/** /**

View File

@ -0,0 +1,51 @@
package com.aizuda.snailjob.server.retry.task.support.request;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.net.url.UrlQuery;
import com.aizuda.snailjob.common.core.constant.SystemConstants;
import com.aizuda.snailjob.common.core.model.SnailJobRequest;
import com.aizuda.snailjob.common.core.model.SnailJobRpcResult;
import com.aizuda.snailjob.common.core.util.JsonUtil;
import com.aizuda.snailjob.common.log.SnailJobLog;
import com.aizuda.snailjob.server.common.convert.RetryResponseVOConverter;
import com.aizuda.snailjob.server.common.exception.SnailJobServerException;
import com.aizuda.snailjob.server.common.handler.PostHttpRequestHandler;
import com.aizuda.snailjob.server.common.vo.RetryResponseVO;
import com.aizuda.snailjob.template.datasource.persistence.mapper.RetryMapper;
import com.aizuda.snailjob.template.datasource.persistence.po.Retry;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class OpenApiGetRetryDetailRequestHandler extends PostHttpRequestHandler {
private final RetryMapper retryMapper;
@Override
public SnailJobRpcResult doHandler(String content, UrlQuery query, HttpHeaders headers) {
SnailJobLog.LOCAL.debug("query retry content:[{}]", content);
SnailJobRequest retryRequest = JsonUtil.parseObject(content, SnailJobRequest.class);
Object[] args = retryRequest.getArgs();
Long retryId = JsonUtil.parseObject(JsonUtil.toJsonString(args[0]), Long.class);
Retry retry = retryMapper.selectById(retryId);
Assert.notNull(retry, () -> new SnailJobServerException("未查询到重试任务:[{}].", retryId));
RetryResponseVO retryResponseVO = RetryResponseVOConverter.INSTANCE.convert(retry);
return new SnailJobRpcResult(retryResponseVO, retryRequest.getReqId());
}
@Override
public boolean supports(String path) {
return SystemConstants.HTTP_PATH.OPENAPI_ADD_RETRY.equals(path);
}
@Override
public HttpMethod method() {
return HttpMethod.POST;
}
}

View File

@ -0,0 +1,83 @@
package com.aizuda.snailjob.server.retry.task.support.request;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.net.url.UrlQuery;
import com.aizuda.snailjob.common.core.constant.SystemConstants;
import com.aizuda.snailjob.common.core.enums.StatusEnum;
import com.aizuda.snailjob.common.core.model.SnailJobRequest;
import com.aizuda.snailjob.common.core.model.SnailJobRpcResult;
import com.aizuda.snailjob.common.core.util.JsonUtil;
import com.aizuda.snailjob.common.log.SnailJobLog;
import com.aizuda.snailjob.server.common.enums.RetryTaskExecutorSceneEnum;
import com.aizuda.snailjob.server.common.enums.SyetemTaskTypeEnum;
import com.aizuda.snailjob.server.common.exception.SnailJobServerException;
import com.aizuda.snailjob.server.common.handler.PostHttpRequestHandler;
import com.aizuda.snailjob.server.common.pekko.ActorGenerator;
import com.aizuda.snailjob.server.common.util.DateUtils;
import com.aizuda.snailjob.server.common.vo.RequestTriggerRetryVO;
import com.aizuda.snailjob.server.retry.task.convert.RetryConverter;
import com.aizuda.snailjob.server.retry.task.dto.RetryTaskPrepareDTO;
import com.aizuda.snailjob.template.datasource.access.AccessTemplate;
import com.aizuda.snailjob.template.datasource.persistence.mapper.RetryMapper;
import com.aizuda.snailjob.template.datasource.persistence.po.GroupConfig;
import com.aizuda.snailjob.template.datasource.persistence.po.Retry;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import lombok.RequiredArgsConstructor;
import org.apache.pekko.actor.ActorRef;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Objects;
@Component
@RequiredArgsConstructor
public class OpenApiTriggerRetryRequestHandler extends PostHttpRequestHandler {
private final RetryMapper retryMapper;
private final AccessTemplate accessTemplate;
@Override
public SnailJobRpcResult doHandler(String content, UrlQuery query, HttpHeaders headers) {
SnailJobLog.LOCAL.debug("trigger retry:[{}]", content);
SnailJobRequest retryRequest = JsonUtil.parseObject(content, SnailJobRequest.class);
Object[] args = retryRequest.getArgs();
RequestTriggerRetryVO triggerRetryVO = JsonUtil.parseObject(JsonUtil.toJsonString(args[0]), RequestTriggerRetryVO.class);
Retry retry = retryMapper.selectById(triggerRetryVO.getId());
Assert.notNull(retry, () -> new SnailJobServerException("未查询到重试任务:[{}].", triggerRetryVO.getId()));
long count = accessTemplate.getGroupConfigAccess().count(new LambdaQueryWrapper<GroupConfig>()
.eq(GroupConfig::getGroupName, retry.getGroupName())
.eq(GroupConfig::getNamespaceId, retry.getNamespaceId())
.eq(GroupConfig::getGroupStatus, StatusEnum.YES.getStatus())
);
Assert.isTrue(count > 0, () -> new SnailJobServerException("组:[{}]已经关闭,不支持手动执行.", retry.getGroupName()));
Assert.isTrue(Objects.equals(retry.getTaskType(), SyetemTaskTypeEnum.RETRY.getType()), () -> new SnailJobServerException("没有可执行的任务"));
RetryTaskPrepareDTO retryTaskPrepareDTO = RetryConverter.INSTANCE.toRetryTaskPrepareDTO(retry);
// 设置now表示立即执行
retryTaskPrepareDTO.setNextTriggerAt(DateUtils.toNowMilli());
retryTaskPrepareDTO.setRetryTaskExecutorScene(RetryTaskExecutorSceneEnum.MANUAL_RETRY.getScene());
retryTaskPrepareDTO.setRetryId(retry.getId());
// 准备阶段执行
ActorRef actorRef = ActorGenerator.retryTaskPrepareActor();
actorRef.tell(retryTaskPrepareDTO, actorRef);
return new SnailJobRpcResult(true, retryRequest.getReqId());
}
@Override
public boolean supports(String path) {
return SystemConstants.HTTP_PATH.OPENAPI_TRIGGER_RETRY.equals(path);
}
@Override
public HttpMethod method() {
return HttpMethod.POST;
}
}

View File

@ -0,0 +1,81 @@
package com.aizuda.snailjob.server.retry.task.support.request;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.net.url.UrlQuery;
import com.aizuda.snailjob.common.core.constant.SystemConstants;
import com.aizuda.snailjob.common.core.enums.RetryStatusEnum;
import com.aizuda.snailjob.common.core.model.SnailJobRequest;
import com.aizuda.snailjob.common.core.model.SnailJobRpcResult;
import com.aizuda.snailjob.common.core.util.JsonUtil;
import com.aizuda.snailjob.common.log.SnailJobLog;
import com.aizuda.snailjob.server.common.WaitStrategy;
import com.aizuda.snailjob.server.common.dto.RetryLogMetaDTO;
import com.aizuda.snailjob.server.common.exception.SnailJobServerException;
import com.aizuda.snailjob.server.common.handler.PostHttpRequestHandler;
import com.aizuda.snailjob.server.common.strategy.WaitStrategies;
import com.aizuda.snailjob.server.common.util.DateUtils;
import com.aizuda.snailjob.server.common.vo.RequestUpdateRetryStatusVO;
import com.aizuda.snailjob.server.retry.task.support.RetryTaskConverter;
import com.aizuda.snailjob.template.datasource.access.AccessTemplate;
import com.aizuda.snailjob.template.datasource.persistence.mapper.RetryMapper;
import com.aizuda.snailjob.template.datasource.persistence.po.Retry;
import com.aizuda.snailjob.template.datasource.persistence.po.RetrySceneConfig;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
@RequiredArgsConstructor
public class OpenApiUpdateRetryStatusRequestHandler extends PostHttpRequestHandler {
private final RetryMapper retryMapper;
private final AccessTemplate accessTemplate;
@Override
public SnailJobRpcResult doHandler(String content, UrlQuery query, HttpHeaders headers) {
SnailJobLog.LOCAL.debug("update retry status:[{}]", content);
SnailJobRequest retryRequest = JsonUtil.parseObject(content, SnailJobRequest.class);
Object[] args = retryRequest.getArgs();
RequestUpdateRetryStatusVO updateRetryStatusVO = JsonUtil.parseObject(JsonUtil.toJsonString(args[0]), RequestUpdateRetryStatusVO.class);
RetryStatusEnum retryStatusEnum = RetryStatusEnum.getByStatus(updateRetryStatusVO.getRetryStatus());
Assert.notNull(retryStatusEnum, () -> new SnailJobServerException("重试状态错误. [{}]", updateRetryStatusVO.getRetryStatus()));
Retry retry = retryMapper.selectById(updateRetryStatusVO.getId());
Assert.notNull(retry, () -> new SnailJobServerException("未查询到重试任务:[{}].", retry.getId()));
retry.setRetryStatus(updateRetryStatusVO.getRetryStatus());
// 若恢复重试则需要重新计算下次触发时间
if (RetryStatusEnum.RUNNING == retryStatusEnum) {
RetrySceneConfig retrySceneConfig = accessTemplate.getSceneConfigAccess()
.getSceneConfigByGroupNameAndSceneName(retry.getGroupName(), retry.getSceneName(), retry.getNamespaceId());
WaitStrategies.WaitStrategyContext waitStrategyContext = new WaitStrategies.WaitStrategyContext();
waitStrategyContext.setNextTriggerAt(DateUtils.toNowMilli());
waitStrategyContext.setTriggerInterval(retrySceneConfig.getTriggerInterval());
waitStrategyContext.setDelayLevel(retry.getRetryCount() + 1);
WaitStrategy waitStrategy = WaitStrategies.WaitStrategyEnum.getWaitStrategy(retrySceneConfig.getBackOff());
retry.setNextTriggerAt(waitStrategy.computeTriggerTime(waitStrategyContext));
}
retry.setUpdateDt(LocalDateTime.now());
Assert.isTrue(retryMapper.updateById(retry) == 1, () -> new SnailJobServerException("重试任务状态更新失败:[{}].", retry.getId()));
return new SnailJobRpcResult(true, retryRequest.getReqId());
}
@Override
public boolean supports(String path) {
return SystemConstants.HTTP_PATH.OPENAPI_UPDATE_RETRY_STATUS.equals(path);
}
@Override
public HttpMethod method() {
return HttpMethod.POST;
}
}

View File

@ -35,7 +35,7 @@ import com.aizuda.snailjob.server.web.model.base.PageResult;
import com.aizuda.snailjob.server.web.model.request.*; import com.aizuda.snailjob.server.web.model.request.*;
import com.aizuda.snailjob.server.web.model.response.RetryResponseVO; import com.aizuda.snailjob.server.web.model.response.RetryResponseVO;
import com.aizuda.snailjob.server.web.service.RetryService; import com.aizuda.snailjob.server.web.service.RetryService;
import com.aizuda.snailjob.server.web.service.convert.RetryConverter; import com.aizuda.snailjob.server.retry.task.convert.RetryConverter;
import com.aizuda.snailjob.server.web.service.convert.RetryTaskResponseVOConverter; import com.aizuda.snailjob.server.web.service.convert.RetryTaskResponseVOConverter;
import com.aizuda.snailjob.server.web.service.convert.TaskContextConverter; import com.aizuda.snailjob.server.web.service.convert.TaskContextConverter;
import com.aizuda.snailjob.server.web.util.UserSessionUtils; import com.aizuda.snailjob.server.web.util.UserSessionUtils;

View File

@ -18,7 +18,7 @@ import com.aizuda.snailjob.server.web.model.request.UserSessionVO;
import com.aizuda.snailjob.server.web.model.response.RetryTaskLogMessageResponseVO; import com.aizuda.snailjob.server.web.model.response.RetryTaskLogMessageResponseVO;
import com.aizuda.snailjob.server.web.model.response.RetryTaskResponseVO; import com.aizuda.snailjob.server.web.model.response.RetryTaskResponseVO;
import com.aizuda.snailjob.server.web.service.RetryTaskService; import com.aizuda.snailjob.server.web.service.RetryTaskService;
import com.aizuda.snailjob.server.web.service.convert.RetryConverter; import com.aizuda.snailjob.server.retry.task.convert.RetryConverter;
import com.aizuda.snailjob.server.web.service.convert.RetryTaskLogResponseVOConverter; import com.aizuda.snailjob.server.web.service.convert.RetryTaskLogResponseVOConverter;
import com.aizuda.snailjob.server.web.service.convert.RetryTaskResponseVOConverter; import com.aizuda.snailjob.server.web.service.convert.RetryTaskResponseVOConverter;
import com.aizuda.snailjob.server.web.util.UserSessionUtils; import com.aizuda.snailjob.server.web.util.UserSessionUtils;