---初始化项目
This commit is contained in:
104
powerjob-client/pom.xml
Normal file
104
powerjob-client/pom.xml
Normal file
@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>powerjob</artifactId>
|
||||
<groupId>tech.powerjob</groupId>
|
||||
<version>5.1.2</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>powerjob-client</artifactId>
|
||||
<name>powerjob-client</name>
|
||||
<version>5.1.2</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<junit.version>5.9.1</junit.version>
|
||||
<logback.version>1.2.13</logback.version>
|
||||
<fastjson.version>1.2.83</fastjson.version>
|
||||
<powerjob.common.version>5.1.2</powerjob.common.version>
|
||||
|
||||
<mvn.shade.plugin.version>3.2.4</mvn.shade.plugin.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- fastJson -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- oms-common -->
|
||||
<dependency>
|
||||
<groupId>tech.powerjob</groupId>
|
||||
<artifactId>powerjob-common</artifactId>
|
||||
<version>${powerjob.common.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Junit tests -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- log for test stage -->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- 暂时放弃 shade,打 shade 包一定要非常干净,否则是更大的坑 -->
|
||||
<!--
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>${mvn.shade.plugin.version}</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>okhttp3</pattern>
|
||||
<shadedPattern>shade.powerjob.okhttp3</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>okio</pattern>
|
||||
<shadedPattern>shade.powerjob.okio</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.google</pattern>
|
||||
<shadedPattern>shade.powerjob.com.google</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.apache</pattern>
|
||||
<shadedPattern>shade.powerjob.org.apache</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.alibaba</pattern>
|
||||
<shadedPattern>shade.powerjob.com.alibaba</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
-->
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,71 @@
|
||||
package tech.powerjob.client;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import tech.powerjob.client.common.Protocol;
|
||||
import tech.powerjob.client.extension.ClientExtension;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 客户端配置
|
||||
*
|
||||
* @author 程序帕鲁
|
||||
* @since 2024/2/20
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
public class ClientConfig implements Serializable {
|
||||
|
||||
/**
|
||||
* 执行器 AppName
|
||||
*/
|
||||
private String appName;
|
||||
|
||||
/**
|
||||
* 执行器密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 地址列表,支持格式:
|
||||
* - IP:Port, eg: 192.168.1.1:7700
|
||||
* - 域名, eg: powerjob.apple-inc.com
|
||||
*/
|
||||
private List<String> addressList;
|
||||
|
||||
/**
|
||||
* 客户端通讯协议
|
||||
*/
|
||||
private Protocol protocol = Protocol.HTTP;
|
||||
|
||||
/**
|
||||
* 连接超时时间
|
||||
*/
|
||||
private Integer connectionTimeout;
|
||||
/**
|
||||
* 指定了等待服务器响应数据的最长时间。更具体地说,这是从服务器开始返回响应数据(包括HTTP头和数据)后,客户端读取数据的超时时间
|
||||
*/
|
||||
private Integer readTimeout;
|
||||
/**
|
||||
* 指定了向服务器发送数据的最长时间。这是从客户端开始发送数据(如POST请求的正文)到数据完全发送出去的时间
|
||||
*/
|
||||
private Integer writeTimeout;
|
||||
|
||||
/**
|
||||
* 默认携带的请求头
|
||||
* 用于流量被基础设施识别
|
||||
*/
|
||||
private Map<String, String> defaultHeaders;
|
||||
|
||||
/**
|
||||
* 客户端行为扩展
|
||||
*/
|
||||
private ClientExtension clientExtension;
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
package tech.powerjob.client;
|
||||
|
||||
import tech.powerjob.common.request.http.RunJobRequest;
|
||||
import tech.powerjob.common.request.http.SaveJobInfoRequest;
|
||||
import tech.powerjob.common.request.http.SaveWorkflowNodeRequest;
|
||||
import tech.powerjob.common.request.http.SaveWorkflowRequest;
|
||||
import tech.powerjob.common.request.query.InstancePageQuery;
|
||||
import tech.powerjob.common.request.query.JobInfoQuery;
|
||||
import tech.powerjob.common.response.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* PowerJobClient, the client for OpenAPI.
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2023/3/5
|
||||
*/
|
||||
public interface IPowerJobClient {
|
||||
|
||||
/* ************* Job 区 ************* */
|
||||
|
||||
ResultDTO<SaveJobInfoRequest> exportJob(Long jobId);
|
||||
|
||||
ResultDTO<Long> saveJob(SaveJobInfoRequest request);
|
||||
|
||||
ResultDTO<Long> copyJob(Long jobId);
|
||||
|
||||
ResultDTO<JobInfoDTO> fetchJob(Long jobId);
|
||||
|
||||
ResultDTO<List<JobInfoDTO>> fetchAllJob();
|
||||
|
||||
ResultDTO<List<JobInfoDTO>> queryJob(JobInfoQuery powerQuery);
|
||||
|
||||
ResultDTO<Void> disableJob(Long jobId);
|
||||
|
||||
ResultDTO<Void> enableJob(Long jobId);
|
||||
|
||||
ResultDTO<Void> deleteJob(Long jobId);
|
||||
|
||||
ResultDTO<Long> runJob(Long jobId, String instanceParams, long delayMS);
|
||||
|
||||
PowerResultDTO<Long> runJob(RunJobRequest runJobRequest);
|
||||
|
||||
/* ************* Instance API list ************* */
|
||||
|
||||
ResultDTO<Void> stopInstance(Long instanceId);
|
||||
|
||||
ResultDTO<Void> cancelInstance(Long instanceId);
|
||||
|
||||
ResultDTO<Void> retryInstance(Long instanceId);
|
||||
|
||||
ResultDTO<Integer> fetchInstanceStatus(Long instanceId);
|
||||
|
||||
ResultDTO<InstanceInfoDTO> fetchInstanceInfo(Long instanceId);
|
||||
|
||||
ResultDTO<PageResult<InstanceInfoDTO>> queryInstanceInfo(InstancePageQuery instancePageQuery);
|
||||
|
||||
/* ************* Workflow API list ************* */
|
||||
ResultDTO<Long> saveWorkflow(SaveWorkflowRequest request);
|
||||
|
||||
ResultDTO<Long> copyWorkflow(Long workflowId);
|
||||
|
||||
ResultDTO<List<WorkflowNodeInfoDTO>> saveWorkflowNode(List<SaveWorkflowNodeRequest> requestList);
|
||||
|
||||
ResultDTO<WorkflowInfoDTO> fetchWorkflow(Long workflowId);
|
||||
|
||||
ResultDTO<Void> disableWorkflow(Long workflowId);
|
||||
|
||||
ResultDTO<Void> enableWorkflow(Long workflowId);
|
||||
|
||||
ResultDTO<Void> deleteWorkflow(Long workflowId);
|
||||
|
||||
ResultDTO<Long> runWorkflow(Long workflowId, String initParams, long delayMS);
|
||||
|
||||
/* ************* Workflow Instance API list ************* */
|
||||
|
||||
ResultDTO<Void> stopWorkflowInstance(Long wfInstanceId);
|
||||
|
||||
ResultDTO<Void> retryWorkflowInstance(Long wfInstanceId);
|
||||
|
||||
ResultDTO<Void> markWorkflowNodeAsSuccess(Long wfInstanceId, Long nodeId);
|
||||
|
||||
ResultDTO<WorkflowInstanceInfoDTO> fetchWorkflowInstanceInfo(Long wfInstanceId);
|
||||
}
|
||||
@ -0,0 +1,563 @@
|
||||
package tech.powerjob.client;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import tech.powerjob.client.module.AppAuthRequest;
|
||||
import tech.powerjob.client.module.AppAuthResult;
|
||||
import tech.powerjob.client.service.PowerRequestBody;
|
||||
import tech.powerjob.client.service.RequestService;
|
||||
import tech.powerjob.client.service.impl.ClusterRequestServiceOkHttp3Impl;
|
||||
import tech.powerjob.common.OpenAPIConstant;
|
||||
import tech.powerjob.common.enums.EncryptType;
|
||||
import tech.powerjob.common.enums.InstanceStatus;
|
||||
import tech.powerjob.common.exception.PowerJobException;
|
||||
import tech.powerjob.common.request.http.RunJobRequest;
|
||||
import tech.powerjob.common.request.http.SaveJobInfoRequest;
|
||||
import tech.powerjob.common.request.http.SaveWorkflowNodeRequest;
|
||||
import tech.powerjob.common.request.http.SaveWorkflowRequest;
|
||||
import tech.powerjob.common.request.query.InstancePageQuery;
|
||||
import tech.powerjob.common.request.query.JobInfoQuery;
|
||||
import tech.powerjob.common.response.*;
|
||||
import tech.powerjob.common.serialize.JsonUtils;
|
||||
import tech.powerjob.common.utils.CommonUtils;
|
||||
import tech.powerjob.common.utils.DigestUtils;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static tech.powerjob.client.TypeStore.*;
|
||||
|
||||
/**
|
||||
* PowerJobClient, the client for OpenAPI.
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2020/4/15
|
||||
*/
|
||||
@Slf4j
|
||||
public class PowerJobClient implements IPowerJobClient, Closeable {
|
||||
|
||||
private Long appId;
|
||||
|
||||
private final RequestService requestService;
|
||||
|
||||
public PowerJobClient(ClientConfig config) {
|
||||
|
||||
List<String> addressList = config.getAddressList();
|
||||
String appName = config.getAppName();
|
||||
|
||||
CommonUtils.requireNonNull(addressList, "addressList can't be null!");
|
||||
CommonUtils.requireNonNull(appName, "appName can't be null");
|
||||
|
||||
this.requestService = new ClusterRequestServiceOkHttp3Impl(config);
|
||||
|
||||
AppAuthRequest appAuthRequest = new AppAuthRequest();
|
||||
appAuthRequest.setAppName(appName);
|
||||
appAuthRequest.setEncryptedPassword(DigestUtils.md5(config.getPassword()));
|
||||
appAuthRequest.setEncryptType(EncryptType.MD5.getCode());
|
||||
|
||||
String assertResponse = requestService.request(OpenAPIConstant.AUTH_APP, PowerRequestBody.newJsonRequestBody(appAuthRequest));
|
||||
|
||||
if (StringUtils.isNotEmpty(assertResponse)) {
|
||||
ResultDTO<AppAuthResult> resultDTO = JSON.parseObject(assertResponse, APP_AUTH_RESULT_TYPE);
|
||||
if (resultDTO.isSuccess()) {
|
||||
appId = resultDTO.getData().getAppId();
|
||||
} else {
|
||||
throw new PowerJobException(resultDTO.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (appId == null) {
|
||||
throw new PowerJobException("appId is null, please check your config");
|
||||
}
|
||||
|
||||
log.info("[PowerJobClient] [INIT] {}'s PowerJobClient bootstrap successfully", appName);
|
||||
}
|
||||
/**
|
||||
* Init PowerJobClient with domain, appName and password.
|
||||
*
|
||||
* @param domain like powerjob-server.apple-inc.com (Intranet Domain)
|
||||
* @param appName name of the application
|
||||
* @param password password of the application
|
||||
*/
|
||||
public PowerJobClient(String domain, String appName, String password) {
|
||||
this(new ClientConfig().setAppName(appName).setPassword(password).setAddressList(Lists.newArrayList(domain)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Init PowerJobClient with server address, appName and password.
|
||||
*
|
||||
* @param addressList IP:Port address list, like 192.168.1.1:7700
|
||||
* @param appName name of the application
|
||||
* @param password password of the application
|
||||
*/
|
||||
public PowerJobClient(List<String> addressList, String appName, String password) {
|
||||
this(new ClientConfig().setAppName(appName).setPassword(password).setAddressList(addressList));
|
||||
}
|
||||
|
||||
/* ************* Job 区 ************* */
|
||||
|
||||
/**
|
||||
* Save one Job
|
||||
* When an ID exists in SaveJobInfoRequest, it is an update operation. Otherwise, it is a crate operation.
|
||||
*
|
||||
* @param request Job meta info
|
||||
* @return jobId
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Long> saveJob(SaveJobInfoRequest request) {
|
||||
|
||||
request.setAppId(appId);
|
||||
String post = requestService.request(OpenAPIConstant.SAVE_JOB, PowerRequestBody.newJsonRequestBody(request));
|
||||
return JSON.parseObject(post, LONG_RESULT_TYPE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copy one Job
|
||||
*
|
||||
* @param jobId Job id
|
||||
* @return Id of job copy
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Long> copyJob(Long jobId) {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("jobId", jobId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
|
||||
String post = requestService.request(OpenAPIConstant.COPY_JOB, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, LONG_RESULT_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDTO<SaveJobInfoRequest> exportJob(Long jobId) {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("jobId", jobId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
String post = requestService.request(OpenAPIConstant.EXPORT_JOB, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, SAVE_JOB_INFO_REQUEST_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query JobInfo by jobId
|
||||
*
|
||||
* @param jobId jobId
|
||||
* @return Job meta info
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<JobInfoDTO> fetchJob(Long jobId) {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("jobId", jobId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
String post = requestService.request(OpenAPIConstant.FETCH_JOB, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, JOB_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query all JobInfo
|
||||
*
|
||||
* @return All JobInfo
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<List<JobInfoDTO>> fetchAllJob() {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("appId", appId.toString());
|
||||
String post = requestService.request(OpenAPIConstant.FETCH_ALL_JOB, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, LIST_JOB_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query JobInfo by PowerQuery
|
||||
*
|
||||
* @param powerQuery JobQuery
|
||||
* @return JobInfo
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<List<JobInfoDTO>> queryJob(JobInfoQuery powerQuery) {
|
||||
powerQuery.setAppIdEq(appId);
|
||||
String post = requestService.request(OpenAPIConstant.QUERY_JOB, PowerRequestBody.newJsonRequestBody(powerQuery));
|
||||
return JSON.parseObject(post, LIST_JOB_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable one Job by jobId
|
||||
*
|
||||
* @param jobId jobId
|
||||
* @return Standard return object
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Void> disableJob(Long jobId) {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("jobId", jobId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
String post = requestService.request(OpenAPIConstant.DISABLE_JOB, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, VOID_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable one job by jobId
|
||||
*
|
||||
* @param jobId jobId
|
||||
* @return Standard return object
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Void> enableJob(Long jobId) {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("jobId", jobId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
String post = requestService.request(OpenAPIConstant.ENABLE_JOB, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, VOID_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete one job by jobId
|
||||
*
|
||||
* @param jobId jobId
|
||||
* @return Standard return object
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Void> deleteJob(Long jobId) {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("jobId", jobId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
String post = requestService.request(OpenAPIConstant.DELETE_JOB, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, VOID_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a job once
|
||||
*
|
||||
* @param jobId ID of the job to be run
|
||||
* @param instanceParams Runtime parameters of the job (TaskContext#instanceParams)
|
||||
* @param delayMS Delay time(Milliseconds)
|
||||
* @return instanceId
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Long> runJob(Long jobId, String instanceParams, long delayMS) {
|
||||
|
||||
RunJobRequest runJobRequest = new RunJobRequest().setJobId(jobId).setInstanceParams(instanceParams).setDelay(delayMS);
|
||||
return runJob(runJobRequest);
|
||||
}
|
||||
|
||||
public ResultDTO<Long> runJob(Long jobId) {
|
||||
return runJob(jobId, null, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PowerResultDTO<Long> runJob(RunJobRequest runJobRequest) {
|
||||
runJobRequest.setAppId(appId);
|
||||
String post = requestService.request(OpenAPIConstant.RUN_JOB2, PowerRequestBody.newJsonRequestBody(runJobRequest));
|
||||
return JSON.parseObject(post, LONG_POWER_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/* ************* Instance API list ************* */
|
||||
|
||||
/**
|
||||
* Stop one job instance
|
||||
*
|
||||
* @param instanceId instanceId
|
||||
* @return Standard return object
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Void> stopInstance(Long instanceId) {
|
||||
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("instanceId", instanceId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
|
||||
String post = requestService.request(OpenAPIConstant.STOP_INSTANCE, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, VOID_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a job instance that is not yet running
|
||||
* Notice:There is a time interval between the call interface time and the expected execution time of the job instance to be cancelled, otherwise reliability is not guaranteed
|
||||
*
|
||||
* @param instanceId instanceId
|
||||
* @return Standard return object
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Void> cancelInstance(Long instanceId) {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("instanceId", instanceId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
String post = requestService.request(OpenAPIConstant.CANCEL_INSTANCE, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, VOID_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry failed job instance
|
||||
* Notice: Only job instance with completion status (success, failure, manually stopped, cancelled) can be retried, and retries of job instances within workflows are not supported yet.
|
||||
*
|
||||
* @param instanceId instanceId
|
||||
* @return Standard return object
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Void> retryInstance(Long instanceId) {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("instanceId", instanceId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
String post = requestService.request(OpenAPIConstant.RETRY_INSTANCE, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, VOID_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query status about a job instance
|
||||
*
|
||||
* @param instanceId instanceId
|
||||
* @return {@link InstanceStatus}
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Integer> fetchInstanceStatus(Long instanceId) {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("instanceId", instanceId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
String post = requestService.request(OpenAPIConstant.FETCH_INSTANCE_STATUS, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, INTEGER_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query detail about a job instance
|
||||
*
|
||||
* @param instanceId instanceId
|
||||
* @return instance detail
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<InstanceInfoDTO> fetchInstanceInfo(Long instanceId) {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("instanceId", instanceId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
String post = requestService.request(OpenAPIConstant.FETCH_INSTANCE_INFO, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, INSTANCE_RESULT_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDTO<PageResult<InstanceInfoDTO>> queryInstanceInfo(InstancePageQuery instancePageQuery) {
|
||||
instancePageQuery.setAppIdEq(appId);
|
||||
String post = requestService.request(OpenAPIConstant.QUERY_INSTANCE, PowerRequestBody.newJsonRequestBody(instancePageQuery));
|
||||
return JSON.parseObject(post, PAGE_INSTANCE_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/* ************* Workflow API list ************* */
|
||||
|
||||
/**
|
||||
* Save one workflow
|
||||
* When an ID exists in SaveWorkflowRequest, it is an update operation. Otherwise, it is a crate operation.
|
||||
*
|
||||
* @param request Workflow meta info
|
||||
* @return workflowId
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Long> saveWorkflow(SaveWorkflowRequest request) {
|
||||
request.setAppId(appId);
|
||||
// 中坑记录:用 FastJSON 序列化会导致 Server 接收时 pEWorkflowDAG 为 null,无语.jpg
|
||||
String json = JsonUtils.toJSONStringUnsafe(request);
|
||||
String post = requestService.request(OpenAPIConstant.SAVE_WORKFLOW, PowerRequestBody.newJsonRequestBody(json));
|
||||
return JSON.parseObject(post, LONG_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy one workflow
|
||||
*
|
||||
* @param workflowId Workflow id
|
||||
* @return Id of workflow copy
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Long> copyWorkflow(Long workflowId) {
|
||||
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("workflowId", workflowId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
|
||||
String post = requestService.request(OpenAPIConstant.COPY_WORKFLOW, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, LONG_RESULT_TYPE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加工作流节点
|
||||
*
|
||||
* @param requestList Node info list of Workflow
|
||||
* @return Standard return object
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<List<WorkflowNodeInfoDTO>> saveWorkflowNode(List<SaveWorkflowNodeRequest> requestList) {
|
||||
for (SaveWorkflowNodeRequest saveWorkflowNodeRequest : requestList) {
|
||||
saveWorkflowNodeRequest.setAppId(appId);
|
||||
}
|
||||
|
||||
String json = JsonUtils.toJSONStringUnsafe(requestList);
|
||||
String post = requestService.request(OpenAPIConstant.SAVE_WORKFLOW_NODE, PowerRequestBody.newJsonRequestBody(json));
|
||||
return JSON.parseObject(post, WF_NODE_LIST_RESULT_TYPE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Query Workflow by workflowId
|
||||
*
|
||||
* @param workflowId workflowId
|
||||
* @return Workflow meta info
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<WorkflowInfoDTO> fetchWorkflow(Long workflowId) {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("workflowId", workflowId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
String post = requestService.request(OpenAPIConstant.FETCH_WORKFLOW, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, WF_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable Workflow by workflowId
|
||||
*
|
||||
* @param workflowId workflowId
|
||||
* @return Standard return object
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Void> disableWorkflow(Long workflowId) {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("workflowId", workflowId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
String post = requestService.request(OpenAPIConstant.DISABLE_WORKFLOW, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, VOID_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Workflow by workflowId
|
||||
*
|
||||
* @param workflowId workflowId
|
||||
* @return Standard return object
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Void> enableWorkflow(Long workflowId) {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("workflowId", workflowId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
String post = requestService.request(OpenAPIConstant.ENABLE_WORKFLOW, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, VOID_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Workflow by workflowId
|
||||
*
|
||||
* @param workflowId workflowId
|
||||
* @return Standard return object
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Void> deleteWorkflow(Long workflowId) {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("workflowId", workflowId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
String post = requestService.request(OpenAPIConstant.DELETE_WORKFLOW, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, VOID_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a workflow once
|
||||
*
|
||||
* @param workflowId workflowId
|
||||
* @param initParams workflow startup parameters
|
||||
* @param delayMS Delay time(Milliseconds)
|
||||
* @return workflow instanceId
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Long> runWorkflow(Long workflowId, String initParams, long delayMS) {
|
||||
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("workflowId", workflowId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
param.put("delay", String.valueOf(delayMS));
|
||||
|
||||
|
||||
if (StringUtils.isNotEmpty(initParams)) {
|
||||
param.put("initParams", initParams);
|
||||
}
|
||||
String post = requestService.request(OpenAPIConstant.RUN_WORKFLOW, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, LONG_RESULT_TYPE);
|
||||
}
|
||||
|
||||
public ResultDTO<Long> runWorkflow(Long workflowId) {
|
||||
return runWorkflow(workflowId, null, 0);
|
||||
}
|
||||
|
||||
/* ************* Workflow Instance API list ************* */
|
||||
|
||||
/**
|
||||
* Stop one workflow instance
|
||||
*
|
||||
* @param wfInstanceId workflow instanceId
|
||||
* @return Standard return object
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Void> stopWorkflowInstance(Long wfInstanceId) {
|
||||
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("wfInstanceId", wfInstanceId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
|
||||
String post = requestService.request(OpenAPIConstant.STOP_WORKFLOW_INSTANCE, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, VOID_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry one workflow instance
|
||||
*
|
||||
* @param wfInstanceId workflow instanceId
|
||||
* @return Standard return object
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Void> retryWorkflowInstance(Long wfInstanceId) {
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("wfInstanceId", wfInstanceId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
String post = requestService.request(OpenAPIConstant.RETRY_WORKFLOW_INSTANCE, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, VOID_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* mark the workflow node as success
|
||||
*
|
||||
* @param wfInstanceId workflow instanceId
|
||||
* @param nodeId node id
|
||||
* @return Standard return object
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<Void> markWorkflowNodeAsSuccess(Long wfInstanceId, Long nodeId) {
|
||||
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("wfInstanceId", wfInstanceId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
param.put("nodeId", nodeId.toString());
|
||||
|
||||
String post = requestService.request(OpenAPIConstant.MARK_WORKFLOW_NODE_AS_SUCCESS, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, VOID_RESULT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query detail about a workflow instance
|
||||
*
|
||||
* @param wfInstanceId workflow instanceId
|
||||
* @return detail about a workflow
|
||||
*/
|
||||
@Override
|
||||
public ResultDTO<WorkflowInstanceInfoDTO> fetchWorkflowInstanceInfo(Long wfInstanceId) {
|
||||
|
||||
Map<String, String> param = Maps.newHashMap();
|
||||
param.put("wfInstanceId", wfInstanceId.toString());
|
||||
param.put("appId", appId.toString());
|
||||
|
||||
String post = requestService.request(OpenAPIConstant.FETCH_WORKFLOW_INSTANCE_INFO, PowerRequestBody.newFormRequestBody(param));
|
||||
return JSON.parseObject(post, WF_INSTANCE_RESULT_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
requestService.close();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package tech.powerjob.client;
|
||||
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import tech.powerjob.client.module.AppAuthResult;
|
||||
import tech.powerjob.common.request.http.SaveJobInfoRequest;
|
||||
import tech.powerjob.common.response.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* TypeReference store.
|
||||
*
|
||||
* @author tjq
|
||||
* @since 11/7/20
|
||||
*/
|
||||
public class TypeStore {
|
||||
|
||||
public static final TypeReference<ResultDTO<AppAuthResult>> APP_AUTH_RESULT_TYPE = new TypeReference<ResultDTO<AppAuthResult>>(){};
|
||||
public static final TypeReference<ResultDTO<Void>> VOID_RESULT_TYPE = new TypeReference<ResultDTO<Void>>(){};
|
||||
|
||||
public static final TypeReference<ResultDTO<Integer>> INTEGER_RESULT_TYPE = new TypeReference<ResultDTO<Integer>>(){};
|
||||
|
||||
public static final TypeReference<ResultDTO<Long>> LONG_RESULT_TYPE = new TypeReference<ResultDTO<Long>>(){};
|
||||
public static final TypeReference<PowerResultDTO<Long>> LONG_POWER_RESULT_TYPE = new TypeReference<PowerResultDTO<Long>>(){};
|
||||
|
||||
public static final TypeReference<ResultDTO<JobInfoDTO>> JOB_RESULT_TYPE = new TypeReference<ResultDTO<JobInfoDTO>>(){};
|
||||
|
||||
public static final TypeReference<ResultDTO<SaveJobInfoRequest>> SAVE_JOB_INFO_REQUEST_RESULT_TYPE = new TypeReference<ResultDTO<SaveJobInfoRequest>>(){};
|
||||
|
||||
public static final TypeReference<ResultDTO<List<JobInfoDTO>>> LIST_JOB_RESULT_TYPE = new TypeReference<ResultDTO<List<JobInfoDTO>>>(){};
|
||||
|
||||
public static final TypeReference<ResultDTO<InstanceInfoDTO>> INSTANCE_RESULT_TYPE = new TypeReference<ResultDTO<InstanceInfoDTO>>() {};
|
||||
|
||||
public static final TypeReference<ResultDTO<List<InstanceInfoDTO>>> LIST_INSTANCE_RESULT_TYPE = new TypeReference<ResultDTO<List<InstanceInfoDTO>>>(){};
|
||||
|
||||
public static final TypeReference<ResultDTO<PageResult<InstanceInfoDTO>>> PAGE_INSTANCE_RESULT_TYPE = new TypeReference<ResultDTO<PageResult<InstanceInfoDTO>>>(){};
|
||||
|
||||
public static final TypeReference<ResultDTO<WorkflowInfoDTO>> WF_RESULT_TYPE = new TypeReference<ResultDTO<WorkflowInfoDTO>>() {};
|
||||
|
||||
public static final TypeReference<ResultDTO<WorkflowInstanceInfoDTO>> WF_INSTANCE_RESULT_TYPE = new TypeReference<ResultDTO<WorkflowInstanceInfoDTO>>() {};
|
||||
|
||||
public static final TypeReference<ResultDTO<List<WorkflowNodeInfoDTO>>> WF_NODE_LIST_RESULT_TYPE = new TypeReference<ResultDTO<List<WorkflowNodeInfoDTO>>> () {};
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package tech.powerjob.client.common;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Protocol
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/20
|
||||
*/
|
||||
@Getter
|
||||
public enum Protocol {
|
||||
|
||||
HTTP("http"),
|
||||
|
||||
HTTPS("https");
|
||||
|
||||
private final String protocol;
|
||||
|
||||
Protocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package tech.powerjob.client.extension;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 扩展服务
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/8/11
|
||||
*/
|
||||
public interface ClientExtension {
|
||||
|
||||
/**
|
||||
* 动态提供地址,适用于 server 部署在动态集群上的场景
|
||||
* @param context 上下文
|
||||
* @return 地址,格式要求同 ClientConfig#addressList
|
||||
*/
|
||||
List<String> addressProvider(ExtensionContext context);
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package tech.powerjob.client.extension;
|
||||
|
||||
/**
|
||||
* 扩展上下文
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/8/11
|
||||
*/
|
||||
public class ExtensionContext {
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package tech.powerjob.client.module;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* App 鉴权请求
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/19
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class AppAuthRequest implements Serializable {
|
||||
|
||||
/**
|
||||
* 应用名称
|
||||
*/
|
||||
private String appName;
|
||||
/**
|
||||
* 加密后密码
|
||||
*/
|
||||
private String encryptedPassword;
|
||||
|
||||
/**
|
||||
* 加密类型
|
||||
*/
|
||||
private String encryptType;
|
||||
|
||||
/**
|
||||
* 额外参数,方便开发者传递其他参数
|
||||
*/
|
||||
private Map<String, Object> extra;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package tech.powerjob.client.module;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* App 鉴权响应
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/21
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class AppAuthResult implements Serializable {
|
||||
|
||||
private Long appId;
|
||||
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 额外参数
|
||||
* 有安全需求的开发者可执行扩展
|
||||
*/
|
||||
private Map<String, Object> extra;
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package tech.powerjob.client.service;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* HTTP 响应
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/8/10
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class HttpResponse implements Serializable {
|
||||
|
||||
private boolean success;
|
||||
|
||||
private int code;
|
||||
|
||||
private String response;
|
||||
|
||||
private Map<String, String> headers;
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package tech.powerjob.client.service;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.Getter;
|
||||
import tech.powerjob.common.enums.MIME;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 请求体
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/8/10
|
||||
*/
|
||||
@Getter
|
||||
public class PowerRequestBody {
|
||||
|
||||
private MIME mime;
|
||||
|
||||
private Object payload;
|
||||
|
||||
private final Map<String, String> headers = Maps.newHashMap();
|
||||
|
||||
private PowerRequestBody() {
|
||||
}
|
||||
|
||||
public static PowerRequestBody newJsonRequestBody(Object data) {
|
||||
PowerRequestBody powerRequestBody = new PowerRequestBody();
|
||||
powerRequestBody.mime = MIME.APPLICATION_JSON;
|
||||
powerRequestBody.payload = data;
|
||||
return powerRequestBody;
|
||||
}
|
||||
|
||||
public static PowerRequestBody newFormRequestBody(Map<String, String> form) {
|
||||
PowerRequestBody powerRequestBody = new PowerRequestBody();
|
||||
powerRequestBody.mime = MIME.APPLICATION_FORM;
|
||||
powerRequestBody.payload = form;
|
||||
return powerRequestBody;
|
||||
}
|
||||
|
||||
public void addHeaders(Map<String, String> hs) {
|
||||
if (hs == null || hs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
this.headers.putAll(hs);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package tech.powerjob.client.service;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
/**
|
||||
* 请求服务
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/20
|
||||
*/
|
||||
public interface RequestService extends Closeable {
|
||||
|
||||
|
||||
String request(String path, PowerRequestBody powerRequestBody);
|
||||
}
|
||||
@ -0,0 +1,113 @@
|
||||
package tech.powerjob.client.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import tech.powerjob.client.ClientConfig;
|
||||
import tech.powerjob.client.TypeStore;
|
||||
import tech.powerjob.client.module.AppAuthRequest;
|
||||
import tech.powerjob.client.module.AppAuthResult;
|
||||
import tech.powerjob.client.service.HttpResponse;
|
||||
import tech.powerjob.client.service.PowerRequestBody;
|
||||
import tech.powerjob.common.OpenAPIConstant;
|
||||
import tech.powerjob.common.enums.EncryptType;
|
||||
import tech.powerjob.common.exception.PowerJobException;
|
||||
import tech.powerjob.common.response.ResultDTO;
|
||||
import tech.powerjob.common.utils.DigestUtils;
|
||||
import tech.powerjob.common.utils.MapUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 封装鉴权相关逻辑
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/21
|
||||
*/
|
||||
@Slf4j
|
||||
abstract class AppAuthClusterRequestService extends ClusterRequestService {
|
||||
|
||||
protected AppAuthResult appAuthResult;
|
||||
|
||||
public AppAuthClusterRequestService(ClientConfig config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String request(String path, PowerRequestBody powerRequestBody) {
|
||||
// 若不存在 appAuthResult,则首先进行鉴权
|
||||
if (appAuthResult == null) {
|
||||
refreshAppAuthResult();
|
||||
}
|
||||
|
||||
HttpResponse httpResponse = doRequest(path, powerRequestBody);
|
||||
|
||||
// 如果 auth 成功,则代表请求有效,直接返回
|
||||
String authStatus = MapUtils.getString(httpResponse.getHeaders(), OpenAPIConstant.RESPONSE_HEADER_AUTH_STATUS);
|
||||
// 继续尝试获取转为小写之后的 auth header (Nginx代理默认会将自定义header转为纯小写, 实现针对该情况的兼容)
|
||||
if (StringUtils.isEmpty(authStatus)) {
|
||||
authStatus = MapUtils.getString(httpResponse.getHeaders(),
|
||||
OpenAPIConstant.RESPONSE_HEADER_AUTH_STATUS.toLowerCase());
|
||||
}
|
||||
if (Boolean.TRUE.toString().equalsIgnoreCase(authStatus)) {
|
||||
return httpResponse.getResponse();
|
||||
}
|
||||
|
||||
// 否则请求无效,刷新鉴权后重新请求
|
||||
log.warn("[PowerJobClient] auth failed[authStatus: {}], try to refresh the auth info", authStatus);
|
||||
refreshAppAuthResult();
|
||||
httpResponse = doRequest(path, powerRequestBody);
|
||||
|
||||
// 只要请求不失败,直接返回(如果鉴权失败则返回鉴权错误信息,server 保证 response 永远非空)
|
||||
return httpResponse.getResponse();
|
||||
}
|
||||
|
||||
private HttpResponse doRequest(String path, PowerRequestBody powerRequestBody) {
|
||||
|
||||
// 添加鉴权信息
|
||||
Map<String, String> authHeaders = buildAuthHeader();
|
||||
powerRequestBody.addHeaders(authHeaders);
|
||||
|
||||
HttpResponse httpResponse = clusterHaRequest(path, powerRequestBody);
|
||||
|
||||
// 任何请求不成功,都直接报错
|
||||
if (!httpResponse.isSuccess()) {
|
||||
throw new PowerJobException("REMOTE_SERVER_INNER_EXCEPTION");
|
||||
}
|
||||
return httpResponse;
|
||||
}
|
||||
|
||||
private Map<String, String> buildAuthHeader() {
|
||||
Map<String, String> authHeader = Maps.newHashMap();
|
||||
authHeader.put(OpenAPIConstant.REQUEST_HEADER_APP_ID, String.valueOf(appAuthResult.getAppId()));
|
||||
authHeader.put(OpenAPIConstant.REQUEST_HEADER_ACCESS_TOKEN, appAuthResult.getToken());
|
||||
return authHeader;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void refreshAppAuthResult() {
|
||||
AppAuthRequest appAuthRequest = buildAppAuthRequest();
|
||||
HttpResponse httpResponse = clusterHaRequest(OpenAPIConstant.AUTH_APP, PowerRequestBody.newJsonRequestBody(appAuthRequest));
|
||||
if (!httpResponse.isSuccess()) {
|
||||
throw new PowerJobException("AUTH_APP_EXCEPTION!");
|
||||
}
|
||||
ResultDTO<AppAuthResult> authResultDTO = JSONObject.parseObject(httpResponse.getResponse(), TypeStore.APP_AUTH_RESULT_TYPE);
|
||||
if (!authResultDTO.isSuccess()) {
|
||||
throw new PowerJobException("AUTH_FAILED_" + authResultDTO.getMessage());
|
||||
}
|
||||
|
||||
log.warn("[PowerJobClient] refresh auth info successfully!");
|
||||
this.appAuthResult = authResultDTO.getData();
|
||||
}
|
||||
|
||||
protected AppAuthRequest buildAppAuthRequest() {
|
||||
AppAuthRequest appAuthRequest = new AppAuthRequest();
|
||||
appAuthRequest.setAppName(config.getAppName());
|
||||
appAuthRequest.setEncryptedPassword(DigestUtils.md5(config.getPassword()));
|
||||
appAuthRequest.setEncryptType(EncryptType.MD5.getCode());
|
||||
return appAuthRequest;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,140 @@
|
||||
package tech.powerjob.client.service.impl;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import tech.powerjob.client.ClientConfig;
|
||||
import tech.powerjob.client.extension.ClientExtension;
|
||||
import tech.powerjob.client.extension.ExtensionContext;
|
||||
import tech.powerjob.client.service.HttpResponse;
|
||||
import tech.powerjob.client.service.PowerRequestBody;
|
||||
import tech.powerjob.client.service.RequestService;
|
||||
import tech.powerjob.common.OpenAPIConstant;
|
||||
import tech.powerjob.common.exception.PowerJobException;
|
||||
import tech.powerjob.common.utils.CollectionUtils;
|
||||
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.io.IOException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 集群请求服务
|
||||
* 封装网络相关通用逻辑
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/21
|
||||
*/
|
||||
@Slf4j
|
||||
abstract class ClusterRequestService implements RequestService {
|
||||
|
||||
protected final ClientConfig config;
|
||||
|
||||
/**
|
||||
* 当前地址(上次请求成功的地址)
|
||||
*/
|
||||
protected String currentAddress;
|
||||
|
||||
/**
|
||||
* 地址格式
|
||||
* 协议://域名/OpenAPI/子路径
|
||||
*/
|
||||
protected static final String URL_PATTERN = "%s://%s%s%s";
|
||||
|
||||
/**
|
||||
* 默认超时时间
|
||||
*/
|
||||
protected static final Integer DEFAULT_TIMEOUT_SECONDS = 2;
|
||||
|
||||
protected static final int HTTP_SUCCESS_CODE = 200;
|
||||
|
||||
public ClusterRequestService(ClientConfig config) {
|
||||
this.config = config;
|
||||
this.currentAddress = config.getAddressList().get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 具体某一次 HTTP 请求的实现
|
||||
* @param url 完整请求地址
|
||||
* @param body 请求体
|
||||
* @return 响应
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
protected abstract HttpResponse sendHttpRequest(String url, PowerRequestBody body) throws IOException;
|
||||
|
||||
/**
|
||||
* 封装集群请求能力
|
||||
* @param path 请求 PATH
|
||||
* @param powerRequestBody 请求体
|
||||
* @return 响应
|
||||
*/
|
||||
protected HttpResponse clusterHaRequest(String path, PowerRequestBody powerRequestBody) {
|
||||
|
||||
// 先尝试默认地址
|
||||
String url = getUrl(path, currentAddress);
|
||||
try {
|
||||
return sendHttpRequest(url, powerRequestBody);
|
||||
} catch (IOException e) {
|
||||
log.warn("[ClusterRequestService] request url:{} failed, reason is {}.", url, e.toString());
|
||||
}
|
||||
|
||||
List<String> addressList = fetchAddressList();
|
||||
|
||||
// 失败,开始重试
|
||||
for (String addr : addressList) {
|
||||
if (Objects.equals(addr, currentAddress)) {
|
||||
continue;
|
||||
}
|
||||
url = getUrl(path, addr);
|
||||
try {
|
||||
HttpResponse res = sendHttpRequest(url, powerRequestBody);
|
||||
log.warn("[ClusterRequestService] server change: from({}) -> to({}).", currentAddress, addr);
|
||||
currentAddress = addr;
|
||||
return res;
|
||||
} catch (IOException e) {
|
||||
log.warn("[ClusterRequestService] request url:{} failed, reason is {}.", url, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
log.error("[ClusterRequestService] do post for path: {} failed because of no server available in {}.", path, addressList);
|
||||
throw new PowerJobException("no server available when send post request");
|
||||
}
|
||||
|
||||
private List<String> fetchAddressList() {
|
||||
|
||||
ClientExtension clientExtension = config.getClientExtension();
|
||||
if (clientExtension != null) {
|
||||
List<String> addressList = clientExtension.addressProvider(new ExtensionContext());
|
||||
if (!CollectionUtils.isEmpty(addressList)) {
|
||||
return addressList;
|
||||
}
|
||||
}
|
||||
|
||||
return config.getAddressList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 不验证证书
|
||||
* X.509 是一个国际标准,定义了公钥证书的格式。这个标准是由国际电信联盟(ITU-T)制定的,用于公钥基础设施(PKI)中数字证书的创建和分发。X.509证书主要用于在公开网络上验证实体的身份,如服务器或客户端的身份验证过程中,确保通信双方是可信的。X.509证书广泛应用于多种安全协议中,包括SSL/TLS,它是实现HTTPS的基础。
|
||||
*/
|
||||
protected static class NoVerifyX509TrustManager implements X509TrustManager {
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] arg0, String arg1) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] arg0, String arg1) {
|
||||
// 不验证
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String getUrl(String path, String address) {
|
||||
String protocol = config.getProtocol().getProtocol();
|
||||
return String.format(URL_PATTERN, protocol, address, OpenAPIConstant.WEB_PATH, path);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,148 @@
|
||||
package tech.powerjob.client.service.impl;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.*;
|
||||
import tech.powerjob.client.ClientConfig;
|
||||
import tech.powerjob.client.common.Protocol;
|
||||
import tech.powerjob.client.service.HttpResponse;
|
||||
import tech.powerjob.client.service.PowerRequestBody;
|
||||
import tech.powerjob.common.OmsConstant;
|
||||
import tech.powerjob.common.serialize.JsonUtils;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.io.IOException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* desc
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/20
|
||||
*/
|
||||
@Slf4j
|
||||
public class ClusterRequestServiceOkHttp3Impl extends AppAuthClusterRequestService {
|
||||
|
||||
private final OkHttpClient okHttpClient;
|
||||
|
||||
|
||||
public ClusterRequestServiceOkHttp3Impl(ClientConfig config) {
|
||||
super(config);
|
||||
|
||||
// 初始化 HTTP 客户端
|
||||
if (Protocol.HTTPS.equals(config.getProtocol())) {
|
||||
okHttpClient = initHttpsNoVerifyClient();
|
||||
} else {
|
||||
okHttpClient = initHttpClient();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpResponse sendHttpRequest(String url, PowerRequestBody powerRequestBody) throws IOException {
|
||||
|
||||
// 添加公共 header
|
||||
powerRequestBody.addHeaders(config.getDefaultHeaders());
|
||||
|
||||
Object obj = powerRequestBody.getPayload();
|
||||
|
||||
RequestBody requestBody = null;
|
||||
|
||||
switch (powerRequestBody.getMime()) {
|
||||
case APPLICATION_JSON:
|
||||
MediaType jsonType = MediaType.parse(OmsConstant.JSON_MEDIA_TYPE);
|
||||
String body = obj instanceof String ? (String) obj : JsonUtils.toJSONStringUnsafe(obj);
|
||||
requestBody = RequestBody.create(jsonType, body);
|
||||
|
||||
break;
|
||||
case APPLICATION_FORM:
|
||||
FormBody.Builder formBuilder = new FormBody.Builder();
|
||||
Map<String, String> formObj = (Map<String, String>) obj;
|
||||
formObj.forEach(formBuilder::add);
|
||||
requestBody = formBuilder.build();
|
||||
}
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.post(requestBody)
|
||||
.headers(Headers.of(powerRequestBody.getHeaders()))
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
try (Response response = okHttpClient.newCall(request).execute()) {
|
||||
|
||||
int code = response.code();
|
||||
HttpResponse httpResponse = new HttpResponse()
|
||||
.setCode(code)
|
||||
.setSuccess(code == HTTP_SUCCESS_CODE);
|
||||
|
||||
ResponseBody body = response.body();
|
||||
if (body != null) {
|
||||
httpResponse.setResponse(body.string());
|
||||
}
|
||||
|
||||
Headers respHeaders = response.headers();
|
||||
Set<String> headerNames = respHeaders.names();
|
||||
Map<String, String> respHeaderMap = Maps.newHashMap();
|
||||
headerNames.forEach(hdKey -> respHeaderMap.put(hdKey, respHeaders.get(hdKey)));
|
||||
|
||||
httpResponse.setHeaders(respHeaderMap);
|
||||
|
||||
return httpResponse;
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private OkHttpClient initHttpClient() {
|
||||
OkHttpClient.Builder okHttpBuilder = commonOkHttpBuilder();
|
||||
return okHttpBuilder.build();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private OkHttpClient initHttpsNoVerifyClient() {
|
||||
|
||||
X509TrustManager trustManager = new NoVerifyX509TrustManager();
|
||||
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom());
|
||||
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
|
||||
|
||||
OkHttpClient.Builder okHttpBuilder = commonOkHttpBuilder();
|
||||
|
||||
// 不需要校验证书
|
||||
okHttpBuilder.sslSocketFactory(sslSocketFactory, trustManager);
|
||||
// 不校验 url中的 hostname
|
||||
okHttpBuilder.hostnameVerifier((String hostname, SSLSession session) -> true);
|
||||
|
||||
|
||||
return okHttpBuilder.build();
|
||||
}
|
||||
|
||||
private OkHttpClient.Builder commonOkHttpBuilder() {
|
||||
return new OkHttpClient.Builder()
|
||||
// 设置读取超时时间
|
||||
.readTimeout(Optional.ofNullable(config.getReadTimeout()).orElse(DEFAULT_TIMEOUT_SECONDS), TimeUnit.SECONDS)
|
||||
// 设置写的超时时间
|
||||
.writeTimeout(Optional.ofNullable(config.getWriteTimeout()).orElse(DEFAULT_TIMEOUT_SECONDS), TimeUnit.SECONDS)
|
||||
// 设置连接超时时间
|
||||
.connectTimeout(Optional.ofNullable(config.getConnectionTimeout()).orElse(DEFAULT_TIMEOUT_SECONDS), TimeUnit.SECONDS)
|
||||
.callTimeout(Optional.ofNullable(config.getConnectionTimeout()).orElse(DEFAULT_TIMEOUT_SECONDS), TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
||||
// 关闭 Dispatcher
|
||||
okHttpClient.dispatcher().executorService().shutdown();
|
||||
// 清理连接池
|
||||
okHttpClient.connectionPool().evictAll();
|
||||
// 清理缓存(如果有使用)
|
||||
Cache cache = okHttpClient.cache();
|
||||
if (cache != null) {
|
||||
cache.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package tech.powerjob.client.test;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import tech.powerjob.client.IPowerJobClient;
|
||||
import tech.powerjob.client.PowerJobClient;
|
||||
|
||||
/**
|
||||
* Initialize OhMyClient
|
||||
*
|
||||
* @author tjq
|
||||
* @since 1/16/21
|
||||
*/
|
||||
public class ClientInitializer {
|
||||
|
||||
protected static IPowerJobClient powerJobClient;
|
||||
|
||||
@BeforeAll
|
||||
public static void initClient() throws Exception {
|
||||
powerJobClient = new PowerJobClient(Lists.newArrayList("127.0.0.1:7700", "127.0.0.1:7701"), "powerjob-worker-samples", "powerjob123");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,172 @@
|
||||
package tech.powerjob.client.test;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tech.powerjob.client.PowerJobClient;
|
||||
import tech.powerjob.common.enums.ExecuteType;
|
||||
import tech.powerjob.common.enums.ProcessorType;
|
||||
import tech.powerjob.common.enums.TimeExpressionType;
|
||||
import tech.powerjob.common.request.http.SaveJobInfoRequest;
|
||||
import tech.powerjob.common.request.query.InstancePageQuery;
|
||||
import tech.powerjob.common.response.InstanceInfoDTO;
|
||||
import tech.powerjob.common.response.JobInfoDTO;
|
||||
import tech.powerjob.common.response.ResultDTO;
|
||||
|
||||
/**
|
||||
* Test cases for {@link PowerJobClient}
|
||||
*
|
||||
* @author tjq
|
||||
* @author Echo009
|
||||
* @since 2020/4/15
|
||||
*/
|
||||
@Slf4j
|
||||
class TestClient extends ClientInitializer {
|
||||
|
||||
public static final long JOB_ID = 1L;
|
||||
|
||||
@Test
|
||||
void testSaveJob() {
|
||||
|
||||
SaveJobInfoRequest newJobInfo = new SaveJobInfoRequest();
|
||||
newJobInfo.setId(JOB_ID);
|
||||
newJobInfo.setJobName("omsOpenAPIJobccccc" + System.currentTimeMillis());
|
||||
newJobInfo.setJobDescription("test OpenAPI" + System.currentTimeMillis());
|
||||
newJobInfo.setJobParams("{'aa':'bb'}");
|
||||
newJobInfo.setTimeExpressionType(TimeExpressionType.CRON);
|
||||
newJobInfo.setTimeExpression("0 0 * * * ? ");
|
||||
newJobInfo.setExecuteType(ExecuteType.STANDALONE);
|
||||
newJobInfo.setProcessorType(ProcessorType.BUILT_IN);
|
||||
newJobInfo.setProcessorInfo("tech.powerjob.samples.processors.StandaloneProcessorDemo");
|
||||
newJobInfo.setDesignatedWorkers("");
|
||||
|
||||
newJobInfo.setMinCpuCores(1.1);
|
||||
newJobInfo.setMinMemorySpace(1.2);
|
||||
newJobInfo.setMinDiskSpace(1.3);
|
||||
|
||||
log.info("[TestClient] [testSaveJob] SaveJobInfoRequest: {}", JSONObject.toJSONString(newJobInfo));
|
||||
|
||||
ResultDTO<Long> resultDTO = powerJobClient.saveJob(newJobInfo);
|
||||
log.info("[TestClient] [testSaveJob] result: {}", JSONObject.toJSONString(resultDTO));
|
||||
Assertions.assertNotNull(resultDTO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCopyJob() {
|
||||
ResultDTO<Long> copyJobRes = powerJobClient.copyJob(JOB_ID);
|
||||
System.out.println(JSONObject.toJSONString(copyJobRes));
|
||||
Assertions.assertNotNull(copyJobRes);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExportJob() {
|
||||
ResultDTO<SaveJobInfoRequest> exportJobRes = powerJobClient.exportJob(JOB_ID);
|
||||
System.out.println(JSONObject.toJSONString(exportJobRes));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchJob() {
|
||||
ResultDTO<JobInfoDTO> fetchJob = powerJobClient.fetchJob(JOB_ID);
|
||||
System.out.println(JSONObject.toJSONString(fetchJob));
|
||||
Assertions.assertNotNull(fetchJob);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDisableJob() {
|
||||
ResultDTO<Void> res = powerJobClient.disableJob(JOB_ID);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEnableJob() {
|
||||
ResultDTO<Void> res = powerJobClient.enableJob(JOB_ID);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteJob() {
|
||||
ResultDTO<Void> res = powerJobClient.deleteJob(JOB_ID);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun() {
|
||||
ResultDTO<Long> res = powerJobClient.runJob(JOB_ID, null, 0);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRunJobDelay() {
|
||||
ResultDTO<Long> res = powerJobClient.runJob(JOB_ID, "this is instanceParams", 60000);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchInstanceInfo() {
|
||||
ResultDTO<InstanceInfoDTO> res = powerJobClient.fetchInstanceInfo(702482902331424832L);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testQueryInstanceInfo() {
|
||||
InstancePageQuery instancePageQuery = new InstancePageQuery();
|
||||
instancePageQuery.setJobIdEq(11L);
|
||||
instancePageQuery.setSortBy("actualTriggerTime");
|
||||
instancePageQuery.setAsc(true);
|
||||
instancePageQuery.setPageSize(3);
|
||||
instancePageQuery.setStatusIn(Lists.newArrayList(1,2,5));
|
||||
TestUtils.output(powerJobClient.queryInstanceInfo(instancePageQuery));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStopInstance() {
|
||||
ResultDTO<Void> res = powerJobClient.stopInstance(702482902331424832L);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchInstanceStatus() {
|
||||
ResultDTO<Integer> res = powerJobClient.fetchInstanceStatus(702482902331424832L);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCancelInstanceInTimeWheel() {
|
||||
ResultDTO<Long> startRes = powerJobClient.runJob(JOB_ID, "start by OhMyClient", 20000);
|
||||
System.out.println("runJob result: " + JSONObject.toJSONString(startRes));
|
||||
ResultDTO<Void> cancelRes = powerJobClient.cancelInstance(startRes.getData());
|
||||
System.out.println("cancelJob result: " + JSONObject.toJSONString(cancelRes));
|
||||
Assertions.assertTrue(cancelRes.isSuccess());
|
||||
}
|
||||
|
||||
// @Test
|
||||
// @SneakyThrows
|
||||
// void testCancelInstanceInDatabase() {
|
||||
// ResultDTO<Long> startRes = powerJobClient.runJob(15L, "start by OhMyClient", 2000000);
|
||||
// System.out.println("runJob result: " + JSONObject.toJSONString(startRes));
|
||||
//
|
||||
// // Restart server manually and clear all the data in time wheeler.
|
||||
// TimeUnit.MINUTES.sleep(1);
|
||||
//
|
||||
// ResultDTO<Void> cancelRes = powerJobClient.cancelInstance(startRes.getData());
|
||||
// System.out.println("cancelJob result: " + JSONObject.toJSONString(cancelRes));
|
||||
// Assertions.assertTrue(cancelRes.isSuccess());
|
||||
// }
|
||||
|
||||
@Test
|
||||
void testRetryInstance() {
|
||||
ResultDTO<Void> res = powerJobClient.retryInstance(169557545206153344L);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package tech.powerjob.client.test;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tech.powerjob.common.response.JobInfoDTO;
|
||||
import tech.powerjob.common.response.ResultDTO;
|
||||
import tech.powerjob.common.utils.CommonUtils;
|
||||
|
||||
/**
|
||||
* 测试容灾能力
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/8/11
|
||||
*/
|
||||
@Slf4j
|
||||
public class TestClusterHA extends ClientInitializer {
|
||||
|
||||
@Test
|
||||
void testHa() {
|
||||
// 人工让 server 启停
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
|
||||
CommonUtils.easySleep(100);
|
||||
|
||||
ResultDTO<JobInfoDTO> jobInfoDTOResultDTO = powerJobClient.fetchJob(1L);
|
||||
|
||||
log.info("[TestClusterHA] response: {}", JSONObject.toJSONString(jobInfoDTOResultDTO));
|
||||
|
||||
if (!jobInfoDTOResultDTO.isSuccess()) {
|
||||
throw new RuntimeException("request failed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package tech.powerjob.client.test;
|
||||
|
||||
import tech.powerjob.common.enums.ExecuteType;
|
||||
import tech.powerjob.common.enums.ProcessorType;
|
||||
import tech.powerjob.common.enums.TimeExpressionType;
|
||||
import tech.powerjob.common.request.http.SaveJobInfoRequest;
|
||||
import tech.powerjob.common.response.ResultDTO;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
|
||||
/**
|
||||
* TestConcurrencyControl
|
||||
*
|
||||
* @author tjq
|
||||
* @since 1/16/21
|
||||
*/
|
||||
class TestConcurrencyControl extends ClientInitializer {
|
||||
|
||||
@Test
|
||||
void testRunJobConcurrencyControl() {
|
||||
|
||||
SaveJobInfoRequest saveJobInfoRequest = new SaveJobInfoRequest();
|
||||
saveJobInfoRequest.setJobName("test concurrency control job");
|
||||
saveJobInfoRequest.setProcessorType(ProcessorType.SHELL);
|
||||
saveJobInfoRequest.setProcessorInfo("pwd");
|
||||
saveJobInfoRequest.setExecuteType(ExecuteType.STANDALONE);
|
||||
saveJobInfoRequest.setTimeExpressionType(TimeExpressionType.API);
|
||||
saveJobInfoRequest.setMaxInstanceNum(1);
|
||||
|
||||
Long jobId = powerJobClient.saveJob(saveJobInfoRequest).getData();
|
||||
|
||||
System.out.println("jobId: " + jobId);
|
||||
|
||||
ForkJoinPool pool = new ForkJoinPool(32);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
String params = "index-" + i;
|
||||
pool.execute(() -> {
|
||||
ResultDTO<Long> res = powerJobClient.runJob(jobId, params, 0);
|
||||
System.out.println(params + ": " + res);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package tech.powerjob.client.test;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tech.powerjob.common.request.http.RunJobRequest;
|
||||
import tech.powerjob.common.request.query.InstancePageQuery;
|
||||
import tech.powerjob.common.response.InstanceInfoDTO;
|
||||
import tech.powerjob.common.response.PageResult;
|
||||
import tech.powerjob.common.response.PowerResultDTO;
|
||||
import tech.powerjob.common.response.ResultDTO;
|
||||
import tech.powerjob.common.serialize.JsonUtils;
|
||||
|
||||
/**
|
||||
* 测试任务实例
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2025/8/17
|
||||
*/
|
||||
@Slf4j
|
||||
public class TestInstance extends ClientInitializer {
|
||||
|
||||
private static final Long jobId = 1L;
|
||||
|
||||
@Test
|
||||
void testOuterKeyAndExtendValue() {
|
||||
String outerKey = "ok_" + System.currentTimeMillis();
|
||||
RunJobRequest runJobRequest = new RunJobRequest()
|
||||
.setJobId(jobId)
|
||||
.setOuterKey(outerKey).setExtendValue("TEST_EXT_VALUE")
|
||||
.setInstanceParams("OpenAPI-Params")
|
||||
.setDelay(1000L);
|
||||
|
||||
PowerResultDTO<Long> runJobResult = powerJobClient.runJob(runJobRequest);
|
||||
log.info("[TestInstance] runJobResult: {}", runJobResult);
|
||||
Long instanceId = runJobResult.getData();
|
||||
|
||||
InstancePageQuery instancePageQuery = new InstancePageQuery();
|
||||
instancePageQuery.setOuterKeyEq(outerKey);
|
||||
ResultDTO<PageResult<InstanceInfoDTO>> pageResultResultDTO = powerJobClient.queryInstanceInfo(instancePageQuery);
|
||||
log.info("[TestInstance] queryInstanceInfo: {}", JsonUtils.toJSONString(pageResultResultDTO));
|
||||
|
||||
assert pageResultResultDTO.getData().getData().get(0).getInstanceId().equals(instanceId);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package tech.powerjob.client.test;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import tech.powerjob.common.request.query.JobInfoQuery;
|
||||
import tech.powerjob.common.enums.ExecuteType;
|
||||
import tech.powerjob.common.enums.ProcessorType;
|
||||
import tech.powerjob.common.response.JobInfoDTO;
|
||||
import tech.powerjob.common.response.ResultDTO;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Test the query method
|
||||
*
|
||||
* @author tjq
|
||||
* @since 1/16/21
|
||||
*/
|
||||
@Slf4j
|
||||
class TestQuery extends ClientInitializer {
|
||||
|
||||
@Test
|
||||
void testFetchAllJob() {
|
||||
ResultDTO<List<JobInfoDTO>> allJobRes = powerJobClient.fetchAllJob();
|
||||
System.out.println(JSON.toJSONString(allJobRes));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testQueryJob() {
|
||||
JobInfoQuery jobInfoQuery = new JobInfoQuery()
|
||||
.setIdGt(-1L)
|
||||
.setIdLt(10086L)
|
||||
.setJobNameLike("DAG")
|
||||
.setGmtModifiedGt(DateUtils.addYears(new Date(), -10))
|
||||
.setGmtCreateLt(DateUtils.addDays(new Date(), 10))
|
||||
.setExecuteTypeIn(Lists.newArrayList(ExecuteType.STANDALONE.getV(), ExecuteType.BROADCAST.getV(), ExecuteType.MAP_REDUCE.getV()))
|
||||
.setProcessorTypeIn(Lists.newArrayList(ProcessorType.BUILT_IN.getV(), ProcessorType.SHELL.getV(), ProcessorType.EXTERNAL.getV()))
|
||||
.setProcessorInfoLike("tech.powerjob");
|
||||
|
||||
ResultDTO<List<JobInfoDTO>> jobQueryResult = powerJobClient.queryJob(jobInfoQuery);
|
||||
System.out.println(JSON.toJSONString(jobQueryResult));
|
||||
System.out.println(jobQueryResult.getData().size());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package tech.powerjob.client.test;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
/**
|
||||
* TestUtils
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/11/21
|
||||
*/
|
||||
public class TestUtils {
|
||||
|
||||
public static void output(Object v) {
|
||||
String str = JSONObject.toJSONString(v);
|
||||
System.out.println(str);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,191 @@
|
||||
package tech.powerjob.client.test;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import tech.powerjob.client.PowerJobClient;
|
||||
import tech.powerjob.common.enums.ExecuteType;
|
||||
import tech.powerjob.common.enums.ProcessorType;
|
||||
import tech.powerjob.common.enums.TimeExpressionType;
|
||||
import tech.powerjob.common.enums.WorkflowNodeType;
|
||||
import tech.powerjob.common.model.PEWorkflowDAG;
|
||||
import tech.powerjob.common.request.http.SaveJobInfoRequest;
|
||||
import tech.powerjob.common.request.http.SaveWorkflowNodeRequest;
|
||||
import tech.powerjob.common.request.http.SaveWorkflowRequest;
|
||||
import tech.powerjob.common.response.ResultDTO;
|
||||
import tech.powerjob.common.response.WorkflowInfoDTO;
|
||||
import tech.powerjob.common.response.WorkflowInstanceInfoDTO;
|
||||
import tech.powerjob.common.response.WorkflowNodeInfoDTO;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Test cases for {@link PowerJobClient} workflow.
|
||||
*
|
||||
* @author tjq
|
||||
* @author Echo009
|
||||
* @since 2020/6/2
|
||||
*/
|
||||
class TestWorkflow extends ClientInitializer {
|
||||
|
||||
private static final long WF_ID = 2;
|
||||
|
||||
@Test
|
||||
void initTestData() {
|
||||
SaveJobInfoRequest base = new SaveJobInfoRequest();
|
||||
base.setJobName("DAG-Node-");
|
||||
base.setTimeExpressionType(TimeExpressionType.WORKFLOW);
|
||||
base.setExecuteType(ExecuteType.STANDALONE);
|
||||
base.setProcessorType(ProcessorType.BUILT_IN);
|
||||
base.setProcessorInfo("tech.powerjob.samples.workflow.WorkflowStandaloneProcessor");
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
SaveJobInfoRequest request = JSONObject.parseObject(JSONObject.toJSONBytes(base), SaveJobInfoRequest.class);
|
||||
request.setJobName(request.getJobName() + i);
|
||||
ResultDTO<Long> res = powerJobClient.saveJob(request);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSaveWorkflow() {
|
||||
|
||||
SaveWorkflowRequest req = new SaveWorkflowRequest();
|
||||
|
||||
req.setWfName("workflow-by-client");
|
||||
req.setWfDescription("created by client");
|
||||
req.setEnable(true);
|
||||
req.setTimeExpressionType(TimeExpressionType.API);
|
||||
|
||||
System.out.println("req ->" + JSONObject.toJSON(req));
|
||||
ResultDTO<Long> res = powerJobClient.saveWorkflow(req);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
|
||||
req.setId(res.getData());
|
||||
|
||||
// 创建节点
|
||||
SaveWorkflowNodeRequest saveWorkflowNodeRequest1 = new SaveWorkflowNodeRequest();
|
||||
saveWorkflowNodeRequest1.setJobId(1L);
|
||||
saveWorkflowNodeRequest1.setNodeName("DAG-Node-1");
|
||||
saveWorkflowNodeRequest1.setType(WorkflowNodeType.JOB.getCode());
|
||||
|
||||
SaveWorkflowNodeRequest saveWorkflowNodeRequest2 = new SaveWorkflowNodeRequest();
|
||||
saveWorkflowNodeRequest2.setJobId(1L);
|
||||
saveWorkflowNodeRequest2.setNodeName("DAG-Node-2");
|
||||
saveWorkflowNodeRequest2.setType(WorkflowNodeType.JOB.getCode());
|
||||
|
||||
|
||||
SaveWorkflowNodeRequest saveWorkflowNodeRequest3 = new SaveWorkflowNodeRequest();
|
||||
saveWorkflowNodeRequest3.setJobId(1L);
|
||||
saveWorkflowNodeRequest3.setNodeName("DAG-Node-3");
|
||||
saveWorkflowNodeRequest3.setType(WorkflowNodeType.JOB.getCode());
|
||||
|
||||
|
||||
List<WorkflowNodeInfoDTO> nodeList = powerJobClient.saveWorkflowNode(Lists.newArrayList(saveWorkflowNodeRequest1,saveWorkflowNodeRequest2,saveWorkflowNodeRequest3)).getData();
|
||||
System.out.println(nodeList);
|
||||
Assertions.assertNotNull(nodeList);
|
||||
|
||||
|
||||
// DAG 图
|
||||
List<PEWorkflowDAG.Node> nodes = Lists.newLinkedList();
|
||||
List<PEWorkflowDAG.Edge> edges = Lists.newLinkedList();
|
||||
|
||||
nodes.add(new PEWorkflowDAG.Node(nodeList.get(0).getId()));
|
||||
nodes.add(new PEWorkflowDAG.Node(nodeList.get(1).getId()));
|
||||
nodes.add(new PEWorkflowDAG.Node(nodeList.get(2).getId()));
|
||||
|
||||
edges.add(new PEWorkflowDAG.Edge(nodeList.get(0).getId(), nodeList.get(1).getId()));
|
||||
edges.add(new PEWorkflowDAG.Edge(nodeList.get(1).getId(), nodeList.get(2).getId()));
|
||||
PEWorkflowDAG peWorkflowDAG = new PEWorkflowDAG(nodes, edges);
|
||||
|
||||
// 保存完整信息
|
||||
req.setDag(peWorkflowDAG);
|
||||
res = powerJobClient.saveWorkflow(req);
|
||||
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCopyWorkflow() {
|
||||
ResultDTO<Long> res = powerJobClient.copyWorkflow(WF_ID);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testDisableWorkflow() {
|
||||
ResultDTO<Void> res = powerJobClient.disableWorkflow(WF_ID);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteWorkflow() {
|
||||
ResultDTO<Void> res = powerJobClient.deleteWorkflow(WF_ID);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEnableWorkflow() {
|
||||
ResultDTO<Void> res = powerJobClient.enableWorkflow(WF_ID);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWorkflowInfo() {
|
||||
ResultDTO<WorkflowInfoDTO> res = powerJobClient.fetchWorkflow(WF_ID);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRunWorkflow() {
|
||||
ResultDTO<Long> res = powerJobClient.runWorkflow(WF_ID, null, 0);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStopWorkflowInstance() {
|
||||
ResultDTO<Void> res = powerJobClient.stopWorkflowInstance(149962433421639744L);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRetryWorkflowInstance() {
|
||||
ResultDTO<Void> res = powerJobClient.retryWorkflowInstance(149962433421639744L);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMarkWorkflowNodeAsSuccess() {
|
||||
ResultDTO<Void> res = powerJobClient.markWorkflowNodeAsSuccess(149962433421639744L, 1L);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWfInstanceInfo() {
|
||||
ResultDTO<WorkflowInstanceInfoDTO> res = powerJobClient.fetchWorkflowInstanceInfo(149962433421639744L);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRunWorkflowPlus() {
|
||||
ResultDTO<Long> res = powerJobClient.runWorkflow(WF_ID, "this is init Params 2", 90000);
|
||||
System.out.println(res);
|
||||
Assertions.assertNotNull(res);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user