@Override public void readFields(DataInput dIn) throws IOException { instanceId = dIn.readUTF(); // Hadoop Configuration has to get its act right int len = dIn.readInt(); byte[] array = new byte[len]; dIn.readFully(array); ByteArrayInputStream bais = new ByteArrayInputStream(array); conf = new XConfiguration(bais); def = new LiteWorkflowApp(); def.readFields(dIn); status = Status.valueOf(dIn.readUTF()); int numExPaths = dIn.readInt(); for (int x = 0; x < numExPaths; x++) { String path = dIn.readUTF(); String nodeName = dIn.readUTF(); boolean isStarted = dIn.readBoolean(); NodeInstance nodeInstance = new NodeInstance(nodeName); nodeInstance.started = isStarted; executionPaths.put(path, nodeInstance); } int numVars = dIn.readInt(); for (int x = 0; x < numVars; x++) { String vName = dIn.readUTF(); String vVal = readBytesAsString(dIn); persistentVars.put(vName, vVal); } refreshLog(); }
private List<String> terminateNodes(Status endStatus) { List<String> endNodes = new ArrayList<String>(); for (Map.Entry<String, NodeInstance> entry : executionPaths.entrySet()) { if (entry.getValue().started) { NodeDef nodeDef = def.getNode(entry.getValue().nodeName); if (!(nodeDef instanceof ControlNodeDef)) { NodeHandler nodeHandler = newInstance(nodeDef.getHandlerClass()); try { if (endStatus == Status.KILLED) { nodeHandler.kill(new Context(nodeDef, entry.getKey(), null)); } else { if (endStatus == Status.FAILED) { nodeHandler.fail(new Context(nodeDef, entry.getKey(), null)); } } endNodes.add(nodeDef.getName()); } catch (Exception ex) { log.warn( XLog.STD, "Error Changing node state to [{0}] for Node [{1}]", endStatus.toString(), nodeDef.getName(), ex); } } } } return endNodes; }
@Override public void write(DataOutput dOut) throws IOException { dOut.writeUTF(instanceId); // Hadoop Configuration has to get its act right ByteArrayOutputStream baos = new ByteArrayOutputStream(); conf.writeXml(baos); baos.close(); byte[] array = baos.toByteArray(); dOut.writeInt(array.length); dOut.write(array); def.write(dOut); dOut.writeUTF(status.toString()); dOut.writeInt(executionPaths.size()); for (Map.Entry<String, NodeInstance> entry : executionPaths.entrySet()) { dOut.writeUTF(entry.getKey()); dOut.writeUTF(entry.getValue().nodeName); dOut.writeBoolean(entry.getValue().started); } dOut.writeInt(persistentVars.size()); for (Map.Entry<String, String> entry : persistentVars.entrySet()) { dOut.writeUTF(entry.getKey()); writeStringAsBytes(entry.getValue(), dOut); } }
private void refreshLog() { XLog.Info.get().setParameter(XLogService.USER, conf.get(OozieClient.USER_NAME)); XLog.Info.get().setParameter(XLogService.GROUP, conf.get(OozieClient.GROUP_NAME)); XLog.Info.get().setParameter(DagXLogInfoService.APP, def.getName()); XLog.Info.get().setParameter(DagXLogInfoService.TOKEN, conf.get(OozieClient.LOG_TOKEN, "")); XLog.Info.get().setParameter(DagXLogInfoService.JOB, instanceId); log = XLog.getLog(getClass()); }
/** * Get NodeDef from workflow instance * * @param executionPath execution path * @return node def */ public NodeDef getNodeDef(String executionPath) { NodeInstance nodeJob = executionPaths.get(executionPath); NodeDef nodeDef = null; if (nodeJob == null) { log.error("invalid execution path [{0}]", executionPath); } else { nodeDef = def.getNode(nodeJob.nodeName); if (nodeDef == null) { log.error("invalid transition [{0}]", nodeJob.nodeName); } } return nodeDef; }
private List<String> killNodes() { List<String> killedNodes = new ArrayList<String>(); for (Map.Entry<String, NodeInstance> entry : executionPaths.entrySet()) { String node = entry.getKey(); NodeInstance nodeInstance = entry.getValue(); if (nodeInstance.started) { NodeDef nodeDef = def.getNode(nodeInstance.nodeName); NodeHandler nodeHandler = newInstance(nodeDef.getHandlerClass()); try { nodeHandler.kill(new Context(nodeDef, node, null)); killedNodes.add(nodeDef.getName()); } catch (Exception ex) { log.warn(XLog.STD, "Error killing node [{0}]", nodeDef.getName(), ex); } } } return killedNodes; }
private String failNode(String nodeName) { String failedNode = null; for (Map.Entry<String, NodeInstance> entry : executionPaths.entrySet()) { String node = entry.getKey(); NodeInstance nodeInstance = entry.getValue(); if (nodeInstance.started && nodeInstance.nodeName.equals(nodeName)) { NodeDef nodeDef = def.getNode(nodeInstance.nodeName); NodeHandler nodeHandler = newInstance(nodeDef.getHandlerClass()); try { nodeHandler.fail(new Context(nodeDef, node, null)); failedNode = nodeDef.getName(); nodeInstance.started = false; } catch (Exception ex) { log.warn(XLog.STD, "Error failing node [{0}]", nodeDef.getName(), ex); } return failedNode; } } return failedNode; }
public synchronized boolean signal(String executionPath, String signalValue) throws WorkflowException { ParamChecker.notEmpty(executionPath, "executionPath"); ParamChecker.notNull(signalValue, "signalValue"); log.debug( XLog.STD, "Signaling job execution path [{0}] signal value [{1}]", executionPath, signalValue); if (status != Status.RUNNING) { throw new WorkflowException(ErrorCode.E0716); } NodeInstance nodeJob = executionPaths.get(executionPath); if (nodeJob == null) { status = Status.FAILED; log.error("invalid execution path [{0}]", executionPath); } NodeDef nodeDef = null; if (!status.isEndState()) { nodeDef = def.getNode(nodeJob.nodeName); if (nodeDef == null) { status = Status.FAILED; log.error("invalid transition [{0}]", nodeJob.nodeName); } } if (!status.isEndState()) { NodeHandler nodeHandler = newInstance(nodeDef.getHandlerClass()); boolean exiting = true; Context context = new Context(nodeDef, executionPath, signalValue); if (!nodeJob.started) { try { nodeHandler.loopDetection(context); exiting = nodeHandler.enter(context); nodeJob.started = true; } catch (WorkflowException ex) { status = Status.FAILED; List<String> killedNodes = terminateNodes(Status.KILLED); if (killedNodes.size() > 1) { log.warn( XLog.STD, "Workflow completed [{0}], killing [{1}] running nodes", status, killedNodes.size()); } throw ex; } } if (exiting) { List<String> pathsToStart = new ArrayList<String>(); List<String> fullTransitions; try { fullTransitions = nodeHandler.multiExit(context); int last = fullTransitions.size() - 1; // TEST THIS if (last >= 0) { String transitionTo = getTransitionNode(fullTransitions.get(last)); if (nodeDef instanceof ForkNodeDef) { transitionTo = "*"; // WF action cannot hold all transitions for a fork. // transitions are hardcoded in the WF app. } persistentVars.put( nodeDef.getName() + WorkflowInstance.NODE_VAR_SEPARATOR + TRANSITION_TO, transitionTo); } } catch (WorkflowException ex) { status = Status.FAILED; throw ex; } if (context.status == Status.KILLED) { status = Status.KILLED; log.debug(XLog.STD, "Completing job, kill node [{0}]", nodeJob.nodeName); } else { if (context.status == Status.FAILED) { status = Status.FAILED; log.debug(XLog.STD, "Completing job, fail node [{0}]", nodeJob.nodeName); } else { if (context.status == Status.SUCCEEDED) { status = Status.SUCCEEDED; log.debug(XLog.STD, "Completing job, end node [{0}]", nodeJob.nodeName); } /* else if (context.status == Status.SUSPENDED) { status = Status.SUSPENDED; log.debug(XLog.STD, "Completing job, end node [{0}]", nodeJob.nodeName); } */ else { for (String fullTransition : fullTransitions) { // this is the whole trick for forking, we need the // executionpath and the transition // in the case of no forking last element of // executionpath is different from transition // in the case of forking they are the same log.debug( XLog.STD, "Exiting node [{0}] with transition[{1}]", nodeJob.nodeName, fullTransition); String execPathFromTransition = getExecutionPath(fullTransition); String transition = getTransitionNode(fullTransition); def.validateTransition(nodeJob.nodeName, transition); NodeInstance nodeJobInPath = executionPaths.get(execPathFromTransition); if ((nodeJobInPath == null) || (!transition.equals(nodeJobInPath.nodeName))) { // TODO explain this IF better // If the WfJob is signaled with the parent // execution executionPath again // The Fork node will execute again.. and replace // the Node WorkflowJobBean // so this is required to prevent that.. // Question : Should we throw an error in this case // ?? executionPaths.put(execPathFromTransition, new NodeInstance(transition)); pathsToStart.add(execPathFromTransition); } } // signal all new synch transitions for (String pathToStart : pathsToStart) { signal(pathToStart, "::synch::"); } } } } } } if (status.isEndState()) { if (status == Status.FAILED) { List<String> failedNodes = terminateNodes(status); log.warn( XLog.STD, "Workflow completed [{0}], failing [{1}] running nodes", status, failedNodes.size()); } else { List<String> killedNodes = terminateNodes(Status.KILLED); if (killedNodes.size() > 1) { log.warn( XLog.STD, "Workflow completed [{0}], killing [{1}] running nodes", status, killedNodes.size()); } } } return status.isEndState(); }