dnet-applications/libs/dnet-wf-service/src/main/java/eu/dnetlib/manager/wf/workflows/procs/ProcessEngine.java

204 lines
6.4 KiB
Java

package eu.dnetlib.manager.wf.workflows.procs;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.common.base.Throwables;
import eu.dnetlib.manager.wf.WorkflowLogger;
import eu.dnetlib.manager.wf.model.WfProcessExecution;
import eu.dnetlib.manager.wf.nodes.ProcessNode;
import eu.dnetlib.manager.wf.notification.EmailSender;
import eu.dnetlib.manager.wf.workflows.graph.GraphNode;
import eu.dnetlib.manager.wf.workflows.procs.WorkflowProcess.Status;
import eu.dnetlib.manager.wf.workflows.util.NodeHelper;
import eu.dnetlib.manager.wf.workflows.util.NodeTokenCallback;
import eu.dnetlib.manager.wf.workflows.util.WorkflowsConstants;
@Service
public class ProcessEngine {
private static final Log log = LogFactory.getLog(ProcessEngine.class);
@Autowired
private NodeHelper nodeHelper;
@Autowired
private EmailSender emailSender;
@Autowired
private WorkflowLogger wfLogger;
public void startProcess(final WorkflowProcess process) {
log.info(process.getGraph());
log.info("Starting workflow: " + process);
final LocalDateTime now = LocalDateTime.now();
process.setStatus(WorkflowProcess.Status.EXECUTING);
process.setStartDate(now);
process.setLastActivityDate(now);
try {
for (final GraphNode node : process.getGraph().startNodes()) {
final ProcessNode pNode = nodeHelper.newProcessNode(node, process, process.getEnv());
final Token token = new Token(node.getName(), newNodeTokenCallback(process, node));
token.getEnv().addAttributes(process.getEnv().getAttributes());
process.getTokens().add(token);
pNode.execute(token);
}
} catch (final Throwable e) {
log.error("WorkflowProcess node instantiation failed", e);
process.setStatus(WorkflowProcess.Status.FAILURE);
}
}
public void releaseToken(final WorkflowProcess process, final GraphNode oldGraphNode, final Token oldToken) {
process.setLastActivityDate(LocalDateTime.now());
try {
for (final GraphNode node : process.getGraph().nextNodes(oldGraphNode, oldToken.getNextArc())) {
if (node.isJoin() || node.isSucessNode()) {
if (!process.getPausedJoinNodeTokens().containsKey(node.getName())) {
process.getPausedJoinNodeTokens().put(node.getName(), new ArrayList<Token>());
}
final List<Token> list = process.getPausedJoinNodeTokens().get(node.getName());
list.add(oldToken);
if (list.size() == process.getGraph().getNumberOfIncomingArcs(node)) {
final Token token = new Token(node.getName(), newNodeTokenCallback(process, node));
token.getEnv().addAttributes(mergeEnvParams(list.toArray(new Token[list.size()])));
final ProcessNode pNode = nodeHelper.newProcessNode(node, process, token.getEnv());
process.getTokens().add(token);
process.setLastActivityDate(LocalDateTime.now());
if (node.isSucessNode()) {
markAsCompleted(process, token);
} else {
pNode.execute(token);
}
}
} else {
final Token token = new Token(node.getName(), newNodeTokenCallback(process, node));
token.getEnv().addAttributes(oldToken.getEnv().getAttributes());
final ProcessNode pNode = nodeHelper.newProcessNode(node, process, token.getEnv());
process.getTokens().add(token);
process.setLastActivityDate(LocalDateTime.now());
pNode.execute(token);
}
}
} catch (final Throwable e) {
log.error("WorkflowProcess node instantiation failed", e);
process.setStatus(WorkflowProcess.Status.FAILURE);
process.setError(e.getMessage());
process.setErrorStacktrace(Throwables.getStackTraceAsString(e));
process.setLastActivityDate(LocalDateTime.now());
}
}
private NodeTokenCallback newNodeTokenCallback(final WorkflowProcess process, final GraphNode node) {
return new NodeTokenCallback() {
@Override
public void onSuccess(final Token token) {
releaseToken(process, node, token);
}
@Override
public void onFail(final Token token) {
completeProcess(process, token);
}
};
}
private Map<String, Object> mergeEnvParams(final Token... tokens) {
final Map<String, Object> map = new HashMap<>();
Arrays.stream(tokens).forEach(t -> map.putAll(t.getEnv().getAttributes()));
return map;
}
private void markAsCompleted(final WorkflowProcess process, final Token token) {
completeProcess(process, token);
}
private void completeProcess(final WorkflowProcess process, final Token token) {
if (token.isActive()) {
if (StringUtils.isNotBlank(token.getError())) {
token.releaseAsFailed(token.getError());
} else {
token.release();
}
}
final LocalDateTime now = token.getEndDate();
process.setLastActivityDate(now);
process.setEndDate(now);
process.setStatus(token.isFailed() ? WorkflowProcess.Status.FAILURE : WorkflowProcess.Status.SUCCESS);
if (token.isFailed()) {
process.setStatus(Status.FAILURE);
process.setError(token.getError());
process.setErrorStacktrace(token.getErrorStackTrace());
process.setLastActivityDate(LocalDateTime.now());
}
if (process.getCallback() != null) {
if (token.isFailed()) {
process.getCallback().onFail();
} else {
process.getCallback().onSuccess();
}
}
final Map<String, String> details = new LinkedHashMap<>();
details.putAll(process.getOutputParams());
details.put(WorkflowsConstants.LOG_WF_PRIORITY, "" + process.getPriority());
details.put(WorkflowsConstants.LOG_WF_ID, process.getWfId());
details.put(WorkflowsConstants.LOG_WF_ID, process.getWfInstanceId());
if (process.getError() != null) {
details.put(WorkflowsConstants.LOG_SYSTEM_ERROR, process.getError());
details.put(WorkflowsConstants.LOG_SYSTEM_ERROR_STACKTRACE, process.getErrorStacktrace());
}
final WfProcessExecution pe = new WfProcessExecution();
pe.setProcessId(process.getId());
pe.setName(process.getName());
pe.setFamily(process.getFamily());
pe.setDsId(process.getDsId());
pe.setDsName(process.getDsName());
pe.setDsApi(process.getDsInterface());
pe.setStartDate(process.getStartDate());
pe.setEndDate(process.getEndDate());
pe.setStatus(process.getStatus().toString());
pe.setDetails(details);
wfLogger.saveProcessExecution(pe);
emailSender.sendMails(process);
}
}