Browse Source
* Supports task instance cache operation * add task plugin cache * use SHA-256 to generate key * Update dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql Co-authored-by: Jay Chung <zhongjiajie955@gmail.com> * Update dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql Co-authored-by: Jay Chung <zhongjiajie955@gmail.com> * Optimizing database Scripts * Optimize clear cache operation Co-authored-by: Jay Chung <zhongjiajie955@gmail.com>3.2.0-release
JieguangZhou
2 years ago
committed by
GitHub
77 changed files with 1151 additions and 24 deletions
@ -0,0 +1,44 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.api.dto.taskInstance; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.api.utils.Result; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
/** |
||||||
|
* task instance success response |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class TaskInstanceRemoveCacheResponse extends Result { |
||||||
|
|
||||||
|
private String cacheKey; |
||||||
|
|
||||||
|
public TaskInstanceRemoveCacheResponse(Result result) { |
||||||
|
super(); |
||||||
|
this.setCode(result.getCode()); |
||||||
|
this.setMsg(result.getMsg()); |
||||||
|
} |
||||||
|
|
||||||
|
public TaskInstanceRemoveCacheResponse(Result result, String cacheKey) { |
||||||
|
super(); |
||||||
|
this.setCode(result.getCode()); |
||||||
|
this.setMsg(result.getMsg()); |
||||||
|
this.cacheKey = cacheKey; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,161 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.dao.utils; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.common.utils.JSONUtils; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.TaskInstance; |
||||||
|
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; |
||||||
|
import org.apache.dolphinscheduler.plugin.task.api.enums.Direct; |
||||||
|
import org.apache.dolphinscheduler.plugin.task.api.model.Property; |
||||||
|
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils; |
||||||
|
import org.apache.commons.lang3.StringUtils; |
||||||
|
import org.apache.commons.lang3.tuple.Pair; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Comparator; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
import java.util.regex.Matcher; |
||||||
|
import java.util.regex.Pattern; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||||
|
|
||||||
|
public class TaskCacheUtils { |
||||||
|
|
||||||
|
private TaskCacheUtils() { |
||||||
|
throw new IllegalStateException("Utility class"); |
||||||
|
} |
||||||
|
|
||||||
|
public static final String MERGE_TAG = "-"; |
||||||
|
|
||||||
|
/** |
||||||
|
* generate cache key for task instance |
||||||
|
* the follow message will be used to generate cache key |
||||||
|
* 2. task version |
||||||
|
* 3. task is cache |
||||||
|
* 4. input VarPool, from upstream task and workflow global parameters |
||||||
|
* @param taskInstance task instance |
||||||
|
* @param taskExecutionContext taskExecutionContext |
||||||
|
* @return cache key |
||||||
|
*/ |
||||||
|
public static String generateCacheKey(TaskInstance taskInstance, TaskExecutionContext taskExecutionContext) { |
||||||
|
List<String> keyElements = new ArrayList<>(); |
||||||
|
keyElements.add(String.valueOf(taskInstance.getTaskCode())); |
||||||
|
keyElements.add(String.valueOf(taskInstance.getTaskDefinitionVersion())); |
||||||
|
keyElements.add(String.valueOf(taskInstance.getIsCache().getCode())); |
||||||
|
keyElements.add(String.valueOf(taskInstance.getEnvironmentConfig())); |
||||||
|
keyElements.add(getTaskInputVarPoolData(taskInstance, taskExecutionContext)); |
||||||
|
String data = StringUtils.join(keyElements, "_"); |
||||||
|
return DigestUtils.sha256Hex(data); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* generate cache key for task instance which is cache execute |
||||||
|
* this key will record which cache task instance will be copied, and cache key will be used |
||||||
|
* tagCacheKey = sourceTaskId + "-" + cacheKey |
||||||
|
* @param sourceTaskId source task id |
||||||
|
* @param cacheKey cache key |
||||||
|
* @return tagCacheKey |
||||||
|
*/ |
||||||
|
public static String generateTagCacheKey(Integer sourceTaskId, String cacheKey) { |
||||||
|
return sourceTaskId + MERGE_TAG + cacheKey; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* revert cache key tag to source task id and cache key |
||||||
|
* @param tagCacheKey cache key |
||||||
|
* @return Pair<Integer, String>, first is source task id, second is cache key |
||||||
|
*/ |
||||||
|
public static Pair<Integer, String> revertCacheKey(String tagCacheKey) { |
||||||
|
Pair<Integer, String> taskIdAndCacheKey; |
||||||
|
if (tagCacheKey == null) { |
||||||
|
taskIdAndCacheKey = Pair.of(-1, ""); |
||||||
|
return taskIdAndCacheKey; |
||||||
|
} |
||||||
|
if (tagCacheKey.contains(MERGE_TAG)) { |
||||||
|
String[] split = tagCacheKey.split(MERGE_TAG); |
||||||
|
if (split.length == 2) { |
||||||
|
taskIdAndCacheKey = Pair.of(Integer.parseInt(split[0]), split[1]); |
||||||
|
} else { |
||||||
|
taskIdAndCacheKey = Pair.of(-1, ""); |
||||||
|
} |
||||||
|
return taskIdAndCacheKey; |
||||||
|
} else { |
||||||
|
return Pair.of(-1, tagCacheKey); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* get hash data of task input var pool |
||||||
|
* there are two parts of task input var pool: from upstream task and workflow global parameters |
||||||
|
* @param taskInstance task instance |
||||||
|
* taskExecutionContext taskExecutionContext |
||||||
|
*/ |
||||||
|
public static String getTaskInputVarPoolData(TaskInstance taskInstance, TaskExecutionContext context) { |
||||||
|
JsonNode taskParams = JSONUtils.parseObject(taskInstance.getTaskParams()); |
||||||
|
|
||||||
|
// The set of input values considered from localParams in the taskParams
|
||||||
|
Set<String> propertyInSet = JSONUtils.toList(taskParams.get("localParams").toString(), Property.class).stream() |
||||||
|
.filter(property -> property.getDirect().equals(Direct.IN)) |
||||||
|
.map(Property::getProp).collect(Collectors.toSet()); |
||||||
|
|
||||||
|
// The set of input values considered from `${var}` form task definition
|
||||||
|
propertyInSet.addAll(getScriptVarInSet(taskInstance)); |
||||||
|
|
||||||
|
// var pool value from upstream task
|
||||||
|
List<Property> varPool = JSONUtils.toList(taskInstance.getVarPool(), Property.class); |
||||||
|
|
||||||
|
// var pool value from workflow global parameters
|
||||||
|
if (context.getPrepareParamsMap() != null) { |
||||||
|
Set<String> taskVarPoolSet = varPool.stream().map(Property::getProp).collect(Collectors.toSet()); |
||||||
|
List<Property> globalContextVarPool = context.getPrepareParamsMap().entrySet().stream() |
||||||
|
.filter(entry -> !taskVarPoolSet.contains(entry.getKey())) |
||||||
|
.map(Map.Entry::getValue) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
varPool.addAll(globalContextVarPool); |
||||||
|
} |
||||||
|
|
||||||
|
// only consider var pool value which is in propertyInSet
|
||||||
|
varPool = varPool.stream() |
||||||
|
.filter(property -> property.getDirect().equals(Direct.IN)) |
||||||
|
.filter(property -> propertyInSet.contains(property.getProp())) |
||||||
|
.sorted(Comparator.comparing(Property::getProp)) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
return JSONUtils.toJsonString(varPool); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* get var in set from task definition |
||||||
|
* @param taskInstance task instance |
||||||
|
* @return var in set |
||||||
|
*/ |
||||||
|
public static List<String> getScriptVarInSet(TaskInstance taskInstance) { |
||||||
|
Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}"); |
||||||
|
Matcher matcher = pattern.matcher(taskInstance.getTaskParams()); |
||||||
|
|
||||||
|
List<String> varInSet = new ArrayList<>(); |
||||||
|
while (matcher.find()) { |
||||||
|
varInSet.add(matcher.group(1)); |
||||||
|
} |
||||||
|
return varInSet; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,172 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.dao.utils; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.common.enums.Flag; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.TaskInstance; |
||||||
|
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; |
||||||
|
import org.apache.dolphinscheduler.plugin.task.api.enums.DataType; |
||||||
|
import org.apache.dolphinscheduler.plugin.task.api.enums.Direct; |
||||||
|
import org.apache.dolphinscheduler.plugin.task.api.model.Property; |
||||||
|
|
||||||
|
import org.apache.commons.lang3.tuple.Pair; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions; |
||||||
|
import org.junit.jupiter.api.BeforeEach; |
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
|
||||||
|
class TaskCacheUtilsTest { |
||||||
|
|
||||||
|
private TaskInstance taskInstance; |
||||||
|
|
||||||
|
private TaskExecutionContext taskExecutionContext; |
||||||
|
|
||||||
|
@BeforeEach |
||||||
|
void setUp() { |
||||||
|
String taskParams = "{\n" + |
||||||
|
" \"localParams\": [\n" + |
||||||
|
" {\n" + |
||||||
|
" \"prop\": \"a\",\n" + |
||||||
|
" \"direct\": \"IN\",\n" + |
||||||
|
" \"type\": \"VARCHAR\",\n" + |
||||||
|
" \"value\": \"\"\n" + |
||||||
|
" },\n" + |
||||||
|
" {\n" + |
||||||
|
" \"prop\": \"b\",\n" + |
||||||
|
" \"direct\": \"IN\",\n" + |
||||||
|
" \"type\": \"VARCHAR\",\n" + |
||||||
|
" \"value\": \"bb\"\n" + |
||||||
|
" }\n" + |
||||||
|
" ],\n" + |
||||||
|
" \"rawScript\": \"echo ${c}\\necho ${d}\",\n" + |
||||||
|
" \"resourceList\": []\n" + |
||||||
|
"}"; |
||||||
|
|
||||||
|
String varPool = "[\n" + |
||||||
|
" {\n" + |
||||||
|
" \"prop\": \"c\",\n" + |
||||||
|
" \"direct\": \"IN\",\n" + |
||||||
|
" \"type\": \"VARCHAR\",\n" + |
||||||
|
" \"value\": \"cc\"\n" + |
||||||
|
" },\n" + |
||||||
|
" {\n" + |
||||||
|
" \"prop\": \"k\",\n" + |
||||||
|
" \"direct\": \"IN\",\n" + |
||||||
|
" \"type\": \"VARCHAR\",\n" + |
||||||
|
" \"value\": \"kk\"\n" + |
||||||
|
" }\n" + |
||||||
|
"]"; |
||||||
|
|
||||||
|
taskInstance = new TaskInstance(); |
||||||
|
taskInstance.setTaskParams(taskParams); |
||||||
|
taskInstance.setVarPool(varPool); |
||||||
|
taskInstance.setTaskCode(123L); |
||||||
|
taskInstance.setTaskDefinitionVersion(1); |
||||||
|
taskInstance.setIsCache(Flag.YES); |
||||||
|
|
||||||
|
taskExecutionContext = new TaskExecutionContext(); |
||||||
|
Property property = new Property(); |
||||||
|
property.setProp("a"); |
||||||
|
property.setDirect(Direct.IN); |
||||||
|
property.setType(DataType.VARCHAR); |
||||||
|
property.setValue("aa"); |
||||||
|
Map<String, Property> prepareParamsMap = new HashMap<>(); |
||||||
|
prepareParamsMap.put("a", property); |
||||||
|
taskExecutionContext.setPrepareParamsMap(prepareParamsMap); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void testRevertCacheKey() { |
||||||
|
Pair<Integer, String> taskIdAndCacheKey1 = TaskCacheUtils.revertCacheKey(null); |
||||||
|
Assertions.assertEquals(Pair.of(-1, ""), taskIdAndCacheKey1); |
||||||
|
|
||||||
|
Pair<Integer, String> taskIdAndCacheKey2 = TaskCacheUtils.revertCacheKey("123"); |
||||||
|
Assertions.assertEquals(Pair.of(-1, "123"), taskIdAndCacheKey2); |
||||||
|
|
||||||
|
Pair<Integer, String> taskIdAndCacheKey3 = TaskCacheUtils.revertCacheKey("1-123"); |
||||||
|
Assertions.assertEquals(Pair.of(1, "123"), taskIdAndCacheKey3); |
||||||
|
|
||||||
|
Pair<Integer, String> taskIdAndCacheKey4 = TaskCacheUtils.revertCacheKey("1-123-4"); |
||||||
|
Assertions.assertEquals(Pair.of(-1, ""), taskIdAndCacheKey4); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void testGetScriptVarInSet() { |
||||||
|
List<String> scriptVarInSet = TaskCacheUtils.getScriptVarInSet(taskInstance); |
||||||
|
List<String> except = new ArrayList<>(Arrays.asList("c", "d")); |
||||||
|
Assertions.assertEquals(except, scriptVarInSet); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void TestGetTaskInputVarPoolData() { |
||||||
|
TaskCacheUtils.getTaskInputVarPoolData(taskInstance, taskExecutionContext); |
||||||
|
// only a=aa and c=cc will influence the result,
|
||||||
|
// b=bb is a fixed value, will be considered in task version
|
||||||
|
// k=kk is not in task params, will be ignored
|
||||||
|
String except = |
||||||
|
"[{\"prop\":\"a\",\"direct\":\"IN\",\"type\":\"VARCHAR\",\"value\":\"aa\"},{\"prop\":\"c\",\"direct\":\"IN\",\"type\":\"VARCHAR\",\"value\":\"cc\"}]"; |
||||||
|
Assertions.assertEquals(except, TaskCacheUtils.getTaskInputVarPoolData(taskInstance, taskExecutionContext)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void TestGenerateCacheKey() { |
||||||
|
String cacheKeyBase = TaskCacheUtils.generateCacheKey(taskInstance, taskExecutionContext); |
||||||
|
Property propertyI = new Property(); |
||||||
|
propertyI.setProp("i"); |
||||||
|
propertyI.setDirect(Direct.IN); |
||||||
|
propertyI.setType(DataType.VARCHAR); |
||||||
|
propertyI.setValue("ii"); |
||||||
|
taskExecutionContext.getPrepareParamsMap().put("i", propertyI); |
||||||
|
String cacheKeyNew = TaskCacheUtils.generateCacheKey(taskInstance, taskExecutionContext); |
||||||
|
// i will not influence the result, because task instance not use it
|
||||||
|
Assertions.assertEquals(cacheKeyBase, cacheKeyNew); |
||||||
|
|
||||||
|
Property propertyD = new Property(); |
||||||
|
propertyD.setProp("d"); |
||||||
|
propertyD.setDirect(Direct.IN); |
||||||
|
propertyD.setType(DataType.VARCHAR); |
||||||
|
propertyD.setValue("dd"); |
||||||
|
taskExecutionContext.getPrepareParamsMap().put("i", propertyD); |
||||||
|
String cacheKeyD = TaskCacheUtils.generateCacheKey(taskInstance, taskExecutionContext); |
||||||
|
// d will influence the result, because task instance use it
|
||||||
|
Assertions.assertNotEquals(cacheKeyBase, cacheKeyD); |
||||||
|
|
||||||
|
taskInstance.setTaskDefinitionVersion(100); |
||||||
|
String cacheKeyE = TaskCacheUtils.generateCacheKey(taskInstance, taskExecutionContext); |
||||||
|
// task definition version is changed, so cache key changed
|
||||||
|
Assertions.assertNotEquals(cacheKeyD, cacheKeyE); |
||||||
|
|
||||||
|
taskInstance.setEnvironmentConfig("export PYTHON_HOME=/bin/python3"); |
||||||
|
String cacheKeyF = TaskCacheUtils.generateCacheKey(taskInstance, taskExecutionContext); |
||||||
|
// EnvironmentConfig is changed, so cache key changed
|
||||||
|
Assertions.assertNotEquals(cacheKeyE, cacheKeyF); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void testGetCacheKey() { |
||||||
|
String cacheKey = TaskCacheUtils.generateTagCacheKey(1, "123"); |
||||||
|
Assertions.assertEquals("1-123", cacheKey); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,109 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.server.master.event; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.common.enums.Flag; |
||||||
|
import org.apache.dolphinscheduler.common.enums.StateEventType; |
||||||
|
import org.apache.dolphinscheduler.common.enums.TaskEventType; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.TaskInstance; |
||||||
|
import org.apache.dolphinscheduler.dao.repository.TaskInstanceDao; |
||||||
|
import org.apache.dolphinscheduler.dao.utils.TaskInstanceUtils; |
||||||
|
import org.apache.dolphinscheduler.server.master.cache.ProcessInstanceExecCacheManager; |
||||||
|
import org.apache.dolphinscheduler.server.master.processor.queue.TaskEvent; |
||||||
|
import org.apache.dolphinscheduler.server.master.runner.WorkflowExecuteRunnable; |
||||||
|
import org.apache.dolphinscheduler.server.master.runner.WorkflowExecuteThreadPool; |
||||||
|
import org.apache.dolphinscheduler.server.master.utils.DataQualityResultOperator; |
||||||
|
import org.apache.dolphinscheduler.service.process.ProcessService; |
||||||
|
|
||||||
|
import java.util.Date; |
||||||
|
import java.util.Optional; |
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
|
||||||
|
@Component |
||||||
|
public class TaskCacheEventHandler implements TaskEventHandler { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ProcessInstanceExecCacheManager processInstanceExecCacheManager; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private WorkflowExecuteThreadPool workflowExecuteThreadPool; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private DataQualityResultOperator dataQualityResultOperator; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ProcessService processService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private TaskInstanceDao taskInstanceDao; |
||||||
|
|
||||||
|
/** |
||||||
|
* handle CACHE task event |
||||||
|
* copy a new task instance from the cache task has been successfully run |
||||||
|
* @param taskEvent task event |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void handleTaskEvent(TaskEvent taskEvent) { |
||||||
|
int taskInstanceId = taskEvent.getTaskInstanceId(); |
||||||
|
int processInstanceId = taskEvent.getProcessInstanceId(); |
||||||
|
|
||||||
|
WorkflowExecuteRunnable workflowExecuteRunnable = processInstanceExecCacheManager.getByProcessInstanceId( |
||||||
|
processInstanceId); |
||||||
|
Optional<TaskInstance> taskInstanceOptional = workflowExecuteRunnable.getTaskInstance(taskInstanceId); |
||||||
|
if (!taskInstanceOptional.isPresent()) { |
||||||
|
return; |
||||||
|
} |
||||||
|
TaskInstance taskInstance = taskInstanceOptional.get(); |
||||||
|
dataQualityResultOperator.operateDqExecuteResult(taskEvent, taskInstance); |
||||||
|
|
||||||
|
TaskInstance cacheTaskInstance = taskInstanceDao.findTaskInstanceById(taskEvent.getCacheTaskInstanceId()); |
||||||
|
|
||||||
|
// keep the task instance fields
|
||||||
|
cacheTaskInstance.setId(taskInstance.getId()); |
||||||
|
cacheTaskInstance.setProcessInstanceId(processInstanceId); |
||||||
|
cacheTaskInstance.setProcessInstanceName(taskInstance.getProcessInstanceName()); |
||||||
|
cacheTaskInstance.setProcessInstance(taskInstance.getProcessInstance()); |
||||||
|
cacheTaskInstance.setProcessDefine(taskInstance.getProcessDefine()); |
||||||
|
cacheTaskInstance.setStartTime(taskInstance.getSubmitTime()); |
||||||
|
cacheTaskInstance.setSubmitTime(taskInstance.getSubmitTime()); |
||||||
|
cacheTaskInstance.setEndTime(new Date()); |
||||||
|
cacheTaskInstance.setFlag(Flag.YES); |
||||||
|
|
||||||
|
TaskInstanceUtils.copyTaskInstance(cacheTaskInstance, taskInstance); |
||||||
|
|
||||||
|
processService.changeOutParam(taskInstance); |
||||||
|
|
||||||
|
taskInstanceDao.updateTaskInstance(taskInstance); |
||||||
|
TaskStateEvent stateEvent = TaskStateEvent.builder() |
||||||
|
.processInstanceId(taskEvent.getProcessInstanceId()) |
||||||
|
.taskInstanceId(taskEvent.getTaskInstanceId()) |
||||||
|
.status(taskEvent.getState()) |
||||||
|
.type(StateEventType.TASK_STATE_CHANGE) |
||||||
|
.build(); |
||||||
|
|
||||||
|
workflowExecuteThreadPool.submitStateEvent(stateEvent); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public TaskEventType getHandleEventType() { |
||||||
|
return TaskEventType.CACHE; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,112 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.server.master.event; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.common.enums.Flag; |
||||||
|
import org.apache.dolphinscheduler.common.utils.JSONUtils; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.ProcessDefinition; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.ProcessInstance; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.TaskInstance; |
||||||
|
import org.apache.dolphinscheduler.dao.repository.TaskInstanceDao; |
||||||
|
import org.apache.dolphinscheduler.server.master.cache.ProcessInstanceExecCacheManager; |
||||||
|
import org.apache.dolphinscheduler.server.master.processor.queue.TaskEvent; |
||||||
|
import org.apache.dolphinscheduler.server.master.runner.WorkflowExecuteRunnable; |
||||||
|
import org.apache.dolphinscheduler.server.master.runner.WorkflowExecuteThreadPool; |
||||||
|
import org.apache.dolphinscheduler.server.master.utils.DataQualityResultOperator; |
||||||
|
import org.apache.dolphinscheduler.service.process.ProcessService; |
||||||
|
|
||||||
|
import java.util.Date; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Optional; |
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions; |
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
import org.junit.jupiter.api.extension.ExtendWith; |
||||||
|
import org.mockito.InjectMocks; |
||||||
|
import org.mockito.Mock; |
||||||
|
import org.mockito.Mockito; |
||||||
|
import org.mockito.junit.jupiter.MockitoExtension; |
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class) |
||||||
|
class TaskCacheEventHandlerTest { |
||||||
|
|
||||||
|
@InjectMocks |
||||||
|
private TaskCacheEventHandler taskCacheEventHandler; |
||||||
|
|
||||||
|
@Mock |
||||||
|
private ProcessInstanceExecCacheManager processInstanceExecCacheManager; |
||||||
|
|
||||||
|
@Mock |
||||||
|
private WorkflowExecuteThreadPool workflowExecuteThreadPool; |
||||||
|
|
||||||
|
@Mock |
||||||
|
private DataQualityResultOperator dataQualityResultOperator; |
||||||
|
|
||||||
|
@Mock |
||||||
|
private ProcessService processService; |
||||||
|
|
||||||
|
@Mock |
||||||
|
private TaskInstanceDao taskInstanceDao; |
||||||
|
|
||||||
|
@Test |
||||||
|
void testHandleTaskEvent() { |
||||||
|
TaskEvent taskEvent = Mockito.mock(TaskEvent.class); |
||||||
|
int processInstanceId = 1; |
||||||
|
int taskInstanceId = 2; |
||||||
|
int cacheTaskInstanceId = 3; |
||||||
|
int cacheProcessInstanceId = 4; |
||||||
|
|
||||||
|
Mockito.when(taskEvent.getTaskInstanceId()).thenReturn(taskInstanceId); |
||||||
|
Mockito.when(taskEvent.getProcessInstanceId()).thenReturn(processInstanceId); |
||||||
|
Mockito.when(taskEvent.getCacheTaskInstanceId()).thenReturn(cacheTaskInstanceId); |
||||||
|
|
||||||
|
TaskInstance cacheTaskInstance = new TaskInstance(); |
||||||
|
cacheTaskInstance.setId(cacheTaskInstanceId); |
||||||
|
cacheTaskInstance.setProcessInstanceId(cacheProcessInstanceId); |
||||||
|
cacheTaskInstance.setTaskParams(JSONUtils.toJsonString(new HashMap<>())); |
||||||
|
|
||||||
|
Mockito.when(taskInstanceDao.findTaskInstanceById(cacheTaskInstanceId)).thenReturn(cacheTaskInstance); |
||||||
|
|
||||||
|
WorkflowExecuteRunnable workflowExecuteRunnable = Mockito.mock(WorkflowExecuteRunnable.class); |
||||||
|
Mockito.when(processInstanceExecCacheManager.getByProcessInstanceId(processInstanceId)) |
||||||
|
.thenReturn(workflowExecuteRunnable); |
||||||
|
Optional<TaskInstance> taskInstanceOptional = Mockito.mock(Optional.class); |
||||||
|
Mockito.when(workflowExecuteRunnable.getTaskInstance(taskInstanceId)).thenReturn(taskInstanceOptional); |
||||||
|
Mockito.when(taskInstanceOptional.isPresent()).thenReturn(true); |
||||||
|
|
||||||
|
TaskInstance taskInstance = new TaskInstance(); |
||||||
|
taskInstance.setTaskParams(JSONUtils.toJsonString(new HashMap<>())); |
||||||
|
taskInstance.setId(taskInstanceId); |
||||||
|
taskInstance.setProcessInstanceId(processInstanceId); |
||||||
|
taskInstance.setProcessInstanceName("test"); |
||||||
|
ProcessInstance processInstance = new ProcessInstance(); |
||||||
|
taskInstance.setProcessInstance(processInstance); |
||||||
|
ProcessDefinition processDefinition = new ProcessDefinition(); |
||||||
|
taskInstance.setProcessDefine(processDefinition); |
||||||
|
taskInstance.setSubmitTime(new Date()); |
||||||
|
|
||||||
|
Mockito.when(taskInstanceOptional.get()).thenReturn(taskInstance); |
||||||
|
|
||||||
|
taskCacheEventHandler.handleTaskEvent(taskEvent); |
||||||
|
|
||||||
|
Assertions.assertEquals(Flag.YES, taskInstance.getFlag()); |
||||||
|
Assertions.assertEquals(taskInstanceId, taskInstance.getId()); |
||||||
|
Assertions.assertEquals(processInstanceId, taskInstance.getProcessInstanceId()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
import { useI18n } from 'vue-i18n' |
||||||
|
import type { IJsonItem } from '../types' |
||||||
|
|
||||||
|
export function useCache(): IJsonItem { |
||||||
|
const { t } = useI18n() |
||||||
|
return { |
||||||
|
type: 'switch', |
||||||
|
field: 'isCache', |
||||||
|
name: t('project.node.is_cache'), |
||||||
|
span: 12 |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue