Source:
<code>public void run() { final long submitTime = flow.getExecutableFlow().getSubmitTime(); this.execMetrics .addFlowTimeToStart(submitTime == -1 ? -1 : System.currentTimeMillis() - submitTime); try { if (this.executorService == null) { this.executorService = Executors.newFixedThreadPool(this.numJobThreads); } setupFlowExecution(); this.flow.setStartTime(System.currentTimeMillis()); this.logger.info("Updating initial flow directory."); updateFlow(); this.logger.info("Fetching job and shared properties."); if (!FlowLoaderUtils.isAzkabanFlowVersion20(this.flow.getAzkabanFlowVersion())) { loadAllProperties(); } this.fireEventListeners( Event.create(this, EventType.FLOW_STARTED, new EventData(this.getExecutableFlow()))); runFlow(); } catch (final Throwable t) { if (this.logger != null) { this.logger .error("An error has occurred during the running of the flow. Quiting.", t); } this.flow.setStatus(Status.FAILED); } finally { try { if (this.watcher != null) { this.logger.info("Watcher is attached. Stopping watcher."); this.watcher.stopWatcher(); this.logger .info("Watcher cancelled status is " + this.watcher.isWatchCancelled()); } this.flow.setEndTime(System.currentTimeMillis()); this.logger.info("Setting end time for flow " + this.execId + " to " + System.currentTimeMillis()); closeLogger(); <START> updateFlow(); <END> } finally { reportFlowFinishedMetrics(); this.fireEventListeners( Event.create(this, EventType.FLOW_FINISHED, new EventData(this.flow))); this.logger .info("Created " + EventType.FLOW_FINISHED + " event for " + flow.getExecutionId()); if (this.azkabanProps.getBoolean(ConfigurationKeys.AZKABAN_POLL_MODEL, false)) { ExecutionControllerUtils.alertUserOnFlowFinished(this.flow, this.alerterHolder, ExecutionControllerUtils.getFinalizeFlowReasons("Flow finished", null)); } } } }</code><technical_language>Calling this in finally means flow status updated properly... is wise do in finally *and* rely flow status mark right metric</technical_language>

Target:
public void run() { try { if (this.executorService == null) { this.executorService = Executors.newFixedThreadPool(this.numJobThreads); } setupFlowExecution(); this.flow.setStartTime(System.currentTimeMillis()); this.logger.info("Updating initial flow directory."); updateFlow(); this.logger.info("Fetching job and shared properties."); if (!FlowLoaderUtils.isAzkabanFlowVersion20(this.flow.getAzkabanFlowVersion())) { loadAllProperties(); } this.fireEventListeners( Event.create(this, EventType.FLOW_STARTED, new EventData(this.getExecutableFlow()))); runFlow(); } catch (final Throwable t) { if (this.logger != null) { this.logger .error("An error has occurred during the running of the flow. Quiting.", t); } if (Status.KILLING.equals(this.flow.getStatus())) { this.execMetrics.decrementFlowKillingCount(); } this.flow.setStatus(Status.FAILED); } finally { try { if (this.watcher != null) { this.logger.info("Watcher is attached. Stopping watcher."); this.watcher.stopWatcher(); this.logger .info("Watcher cancelled status is " + this.watcher.isWatchCancelled()); } this.flow.setEndTime(System.currentTimeMillis()); this.logger.info("Setting end time for flow " + this.execId + " to " + System.currentTimeMillis()); closeLogger(); updateFlow(); } finally { reportFlowFinishedMetrics(); this.fireEventListeners( Event.create(this, EventType.FLOW_FINISHED, new EventData(this.flow))); this.logger .info("Created " + EventType.FLOW_FINISHED + " event for " + flow.getExecutionId()); if (this.azkabanProps.getBoolean(ConfigurationKeys.AZKABAN_POLL_MODEL, false)) { ExecutionControllerUtils.alertUserOnFlowFinished(this.flow, this.alerterHolder, ExecutionControllerUtils.getFinalizeFlowReasons("Flow finished", null)); } } } }