com.weibo.rill.flow.olympicene.traversal.runners.SuspenseTaskRunner Maven / Gradle / Ivy
/*
* Copyright 2021-2023 Weibo, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.weibo.rill.flow.olympicene.traversal.runners;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.weibo.rill.flow.interfaces.model.task.TaskInfo;
import com.weibo.rill.flow.interfaces.model.task.TaskInvokeMsg;
import com.weibo.rill.flow.interfaces.model.task.TaskStatus;
import com.weibo.rill.flow.olympicene.core.lock.LockerKey;
import com.weibo.rill.flow.olympicene.core.model.NotifyInfo;
import com.weibo.rill.flow.olympicene.core.model.task.ExecutionResult;
import com.weibo.rill.flow.olympicene.core.model.task.SuspenseTask;
import com.weibo.rill.flow.olympicene.core.model.task.TaskCategory;
import com.weibo.rill.flow.olympicene.core.runtime.DAGContextStorage;
import com.weibo.rill.flow.olympicene.core.runtime.DAGInfoStorage;
import com.weibo.rill.flow.olympicene.core.runtime.DAGStorageProcedure;
import com.weibo.rill.flow.olympicene.core.switcher.SwitcherManager;
import com.weibo.rill.flow.olympicene.traversal.utils.ConditionsUtil;
import com.weibo.rill.flow.olympicene.traversal.constant.TraversalErrorCode;
import com.weibo.rill.flow.olympicene.traversal.exception.DAGTraversalException;
import com.weibo.rill.flow.olympicene.traversal.helper.ContextHelper;
import com.weibo.rill.flow.olympicene.traversal.mappings.InputOutputMapping;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
/**
* 方法加锁原因 有两个场景能触发suspense任务执行 可能产生并发
* 1. traversal遍历触发任务
* 2. wakeup调用触发任务
*
* Created by xilong on 2021/4/7.
*/
@Slf4j
public class SuspenseTaskRunner extends AbstractTaskRunner {
public SuspenseTaskRunner(InputOutputMapping inputOutputMapping,
DAGInfoStorage dagInfoStorage,
DAGContextStorage dagContextStorage,
DAGStorageProcedure dagStorageProcedure,
SwitcherManager switcherManager) {
super(inputOutputMapping, dagInfoStorage, dagContextStorage, dagStorageProcedure, switcherManager);
}
@Override
public TaskCategory getCategory() {
return TaskCategory.SUSPENSE;
}
@Override
public String getIcon() {
return "ant-design:pause-circle-outlined";
}
@Override
protected ExecutionResult doRun(String executionId, TaskInfo taskInfo, Map input) {
log.info("suspense task begin to run executionId:{}, taskInfoName:{}", executionId, taskInfo.getName());
ExecutionResult ret = ExecutionResult.builder().build();
dagStorageProcedure.lockAndRun(LockerKey.buildTaskInfoLockName(executionId, taskInfo.getName()), () -> {
// 因为有并发可能 导致收到的input可能为wakeup更新前的值
// wakeup更新可能导致context值发生变化 因此需要取最新context
Map context = ContextHelper.getInstance().getContext(dagContextStorage, executionId, taskInfo);
Map inputRealTime = Maps.newHashMap();
inputMappings(context, inputRealTime, new HashMap<>(), taskInfo.getTask().getInputMappings());
taskInfo.setTaskStatus(TaskStatus.RUNNING);
tryWakeup(executionId, taskInfo, inputRealTime);
tryInterruptSuspense(executionId, taskInfo, inputRealTime);
dagInfoStorage.saveTaskInfos(executionId, ImmutableSet.of(taskInfo));
ret.setInput(inputRealTime);
ret.setTaskStatus(taskInfo.getTaskStatus());
});
log.info("run suspense task completed, executionId:{}, taskInfoName:{}", executionId, taskInfo.getName());
return ret;
}
@Override
public ExecutionResult finish(String executionId, NotifyInfo notifyInfo, Map output) {
String taskInfoName = notifyInfo.getTaskInfoName();
log.info("suspense wakeup begin to run executionId:{}, taskInfoName:{}, output empty:{}",
executionId, taskInfoName, MapUtils.isEmpty(output));
AtomicReference taskInfoRef = new AtomicReference<>();
AtomicReference