use of io.cdap.cdap.api.workflow.WorkflowToken in project cdap by caskdata.
the class WorkflowDriver method executeFork.
private void executeFork(final ApplicationSpecification appSpec, WorkflowForkNode fork, final InstantiatorFactory instantiator, final ClassLoader classLoader, final WorkflowToken token) throws Exception {
CountDownLatch executorTerminateLatch = new CountDownLatch(1);
ExecutorService executorService = createExecutor(fork.getBranches().size(), executorTerminateLatch, "fork-" + fork.getNodeId() + "-%d");
CompletionService<Map.Entry<String, WorkflowToken>> completionService = new ExecutorCompletionService<>(executorService);
try {
for (final List<WorkflowNode> branch : fork.getBranches()) {
completionService.submit(new Callable<Map.Entry<String, WorkflowToken>>() {
@Override
public Map.Entry<String, WorkflowToken> call() throws Exception {
WorkflowToken copiedToken = ((BasicWorkflowToken) token).deepCopy();
executeAll(branch.iterator(), appSpec, instantiator, classLoader, copiedToken);
return Maps.immutableEntry(branch.toString(), copiedToken);
}
});
}
for (int i = 0; i < fork.getBranches().size(); i++) {
try {
Future<Map.Entry<String, WorkflowToken>> forkBranchResult = completionService.take();
Map.Entry<String, WorkflowToken> retValue = forkBranchResult.get();
String branchInfo = retValue.getKey();
WorkflowToken branchToken = retValue.getValue();
((BasicWorkflowToken) token).mergeToken(branchToken);
LOG.trace("Execution of branch {} for fork {} completed.", branchInfo, fork);
} catch (InterruptedException e) {
// Due to workflow abortion, so just break the loop
break;
} catch (ExecutionException e) {
// Unwrap the cause
Throwables.propagateIfPossible(e.getCause(), Exception.class);
throw Throwables.propagate(e.getCause());
}
}
} finally {
// Update the WorkflowToken after the execution of the FORK node completes.
workflowStateWriter.setWorkflowToken(workflowRunId, token);
executorService.shutdownNow();
// Wait for the executor termination
executorTerminateLatch.await();
}
}
use of io.cdap.cdap.api.workflow.WorkflowToken in project cdap by caskdata.
the class MetadataSubscriberServiceTest method testWorkflow.
@Test
public void testWorkflow() throws InterruptedException, ExecutionException, TimeoutException {
ProgramRunId workflowRunId = workflow1.run(RunIds.generate());
// Try to read, should have nothing
Store store = getInjector().getInstance(DefaultStore.class);
WorkflowToken workflowToken = store.getWorkflowToken(workflow1, workflowRunId.getRun());
Assert.assertNull(workflowToken.get("key"));
BasicWorkflowToken token = new BasicWorkflowToken(1024);
token.setCurrentNode("node1");
token.put("key", "value");
// Publish some workflow states
WorkflowStateWriter workflowStateWriter = getInjector().getInstance(MessagingWorkflowStateWriter.class);
workflowStateWriter.setWorkflowToken(workflowRunId, token);
workflowStateWriter.addWorkflowNodeState(workflowRunId, new WorkflowNodeStateDetail("action1", NodeStatus.RUNNING));
// Verify the WorkflowToken
Tasks.waitFor("value", () -> Optional.ofNullable(store.getWorkflowToken(workflow1, workflowRunId.getRun()).get("key")).map(Value::toString).orElse(null), 10, TimeUnit.SECONDS, 100, TimeUnit.MILLISECONDS);
// Verify the workflow node state
Tasks.waitFor(NodeStatus.RUNNING, () -> store.getWorkflowNodeStates(workflowRunId).stream().findFirst().map(WorkflowNodeStateDetail::getNodeStatus).orElse(null), 10, TimeUnit.SECONDS, 100, TimeUnit.MILLISECONDS);
// Update the node state
workflowStateWriter.addWorkflowNodeState(workflowRunId, new WorkflowNodeStateDetail("action1", NodeStatus.COMPLETED));
// Verify the updated node state
Tasks.waitFor(NodeStatus.COMPLETED, () -> store.getWorkflowNodeStates(workflowRunId).stream().findFirst().map(WorkflowNodeStateDetail::getNodeStatus).orElse(null), 10, TimeUnit.SECONDS, 100, TimeUnit.MILLISECONDS);
}
use of io.cdap.cdap.api.workflow.WorkflowToken in project cdap by caskdata.
the class SmartWorkflow method destroy.
@Override
public void destroy() {
WorkflowContext workflowContext = getContext();
PipelineRuntime pipelineRuntime = new PipelineRuntime(workflowContext, workflowMetrics);
// Execute the post actions only if pipeline is not running in preview mode.
if (!workflowContext.getDataTracer(PostAction.PLUGIN_TYPE).isEnabled()) {
for (Map.Entry<String, PostAction> endingActionEntry : postActions.entrySet()) {
String name = endingActionEntry.getKey();
PostAction action = endingActionEntry.getValue();
StageSpec stageSpec = stageSpecs.get(name);
BatchActionContext context = new WorkflowBackedActionContext(workflowContext, pipelineRuntime, stageSpec);
try {
action.run(context);
} catch (Throwable t) {
LOG.error("Error while running post action {}.", name, t);
}
}
}
Map<String, String> connectorDatasets = GSON.fromJson(workflowContext.getWorkflowSpecification().getProperty(Constants.CONNECTOR_DATASETS), STAGE_DATASET_MAP);
// publish all alerts
for (Map.Entry<String, AlertPublisher> alertPublisherEntry : alertPublishers.entrySet()) {
String stageName = alertPublisherEntry.getKey();
AlertPublisher alertPublisher = alertPublisherEntry.getValue();
FileSet alertConnector = workflowContext.getDataset(connectorDatasets.get(stageName));
try (CloseableIterator<Alert> alerts = new AlertReader(alertConnector)) {
if (!alerts.hasNext()) {
continue;
}
StageMetrics stageMetrics = new DefaultStageMetrics(workflowMetrics, stageName);
StageSpec stageSpec = stageSpecs.get(stageName);
AlertPublisherContext alertContext = new DefaultAlertPublisherContext(pipelineRuntime, stageSpec, workflowContext, workflowContext.getAdmin());
alertPublisher.initialize(alertContext);
TrackedIterator<Alert> trackedIterator = new TrackedIterator<>(alerts, stageMetrics, Constants.Metrics.RECORDS_IN);
alertPublisher.publish(trackedIterator);
} catch (Exception e) {
LOG.warn("Stage {} had errors publishing alerts. Alerts may not have been published.", stageName, e);
} finally {
try {
alertPublisher.destroy();
} catch (Exception e) {
LOG.warn("Error destroying alert publisher for stage {}", stageName, e);
}
}
}
ProgramStatus status = getContext().getState().getStatus();
if (status == ProgramStatus.FAILED) {
WRAPPERLOGGER.error("Pipeline '{}' failed.", getContext().getApplicationSpecification().getName());
} else {
WRAPPERLOGGER.info("Pipeline '{}' {}.", getContext().getApplicationSpecification().getName(), status == ProgramStatus.COMPLETED ? "succeeded" : status.name().toLowerCase());
}
MacroEvaluator macroEvaluator = new DefaultMacroEvaluator(pipelineRuntime.getArguments(), workflowContext.getLogicalStartTime(), workflowContext, workflowContext, workflowContext.getNamespace());
// Get resolved plugin properties
Map<String, Map<String, String>> resolvedProperties = new HashMap<>();
for (StageSpec spec : stageSpecs.values()) {
String stageName = spec.getName();
resolvedProperties.put(stageName, workflowContext.getPluginProperties(stageName, macroEvaluator).getProperties());
}
// Add resolved plugin properties to workflow token as a JSON String
workflowContext.getToken().put(RESOLVED_PLUGIN_PROPERTIES_MAP, GSON.toJson(resolvedProperties));
// record only if the Workflow is successful
if (status != ProgramStatus.COMPLETED) {
return;
}
// Collect field operations from each phase
WorkflowToken token = workflowContext.getToken();
List<NodeValue> allNodeValues = token.getAll(Constants.FIELD_OPERATION_KEY_IN_WORKFLOW_TOKEN);
if (allNodeValues.isEmpty()) {
// no field lineage recorded by any stage
return;
}
Map<String, List<FieldOperation>> allStageOperations = new HashMap<>();
for (StageSpec stageSpec : stageSpecs.values()) {
allStageOperations.put(stageSpec.getName(), new ArrayList<>());
}
for (NodeValue nodeValue : allNodeValues) {
Map<String, List<FieldOperation>> stageOperations = GSON.fromJson(nodeValue.getValue().toString(), STAGE_OPERATIONS_MAP);
for (Map.Entry<String, List<FieldOperation>> entry : stageOperations.entrySet()) {
// ignore them
if (allStageOperations.containsKey(entry.getKey())) {
allStageOperations.get(entry.getKey()).addAll(entry.getValue());
}
}
}
FieldLineageProcessor processor = new FieldLineageProcessor(spec);
Set<Operation> processedOperations = processor.validateAndConvert(allStageOperations);
if (!processedOperations.isEmpty()) {
workflowContext.record(processedOperations);
}
}
use of io.cdap.cdap.api.workflow.WorkflowToken in project cdap by caskdata.
the class WorkflowHttpHandler method getWorkflowToken.
@GET
@Path("/apps/{app-id}/workflows/{workflow-id}/runs/{run-id}/nodes/{node-id}/token")
public void getWorkflowToken(HttpRequest request, HttpResponder responder, @PathParam("namespace-id") String namespaceId, @PathParam("app-id") String appId, @PathParam("workflow-id") String workflowId, @PathParam("run-id") String runId, @PathParam("node-id") String nodeId, @QueryParam("scope") @DefaultValue("user") String scope, @QueryParam("key") @DefaultValue("") String key) throws NotFoundException {
WorkflowToken workflowToken = getWorkflowToken(namespaceId, appId, workflowId, runId);
WorkflowToken.Scope tokenScope = WorkflowToken.Scope.valueOf(scope.toUpperCase());
Map<String, Value> workflowTokenFromNode = workflowToken.getAllFromNode(nodeId, tokenScope);
WorkflowTokenNodeDetail tokenAtNode = WorkflowTokenNodeDetail.of(workflowTokenFromNode);
Type workflowTokenNodeDetailType = new TypeToken<WorkflowTokenNodeDetail>() {
}.getType();
if (key.isEmpty()) {
responder.sendJson(HttpResponseStatus.OK, GSON.toJson(tokenAtNode, workflowTokenNodeDetailType));
return;
}
if (!workflowTokenFromNode.containsKey(key)) {
throw new NotFoundException(key);
}
responder.sendJson(HttpResponseStatus.OK, GSON.toJson(WorkflowTokenNodeDetail.of(Collections.singletonMap(key, workflowTokenFromNode.get(key))), workflowTokenNodeDetailType));
}
use of io.cdap.cdap.api.workflow.WorkflowToken in project cdap by caskdata.
the class AppWithMultipleSchedules method addTokens.
private static void addTokens(List<ProgramStatusTriggerInfo> programStatusTriggerInfos, Map<String, String> runtimeArgs, String triggeringKeyNodePair, String key) {
for (ProgramStatusTriggerInfo triggerInfo : programStatusTriggerInfos) {
WorkflowToken token = triggerInfo.getWorkflowToken();
if (token == null) {
continue;
}
String[] keyNode = triggeringKeyNodePair.split(":");
Value value = token.get(keyNode[0], keyNode[1]);
if (value == null) {
continue;
}
runtimeArgs.put(key, value.toString());
}
}
Aggregations