code: @Override
    public void cancelFlow(final ExecutableFlow exFlow, final String userId)
        throws ExecutorManagerException {
      synchronized (exFlow) {
        final Map<Integer, Pair<ExecutionReference, ExecutableFlow>> unfinishedFlows = this.executorLoader
            .fetchUnfinishedFlows();
        if (unfinishedFlows.containsKey(exFlow.getExecutionId())) {
          final Pair<ExecutionReference, ExecutableFlow> pair = unfinishedFlows
              .get(exFlow.getExecutionId());
          if (pair.getFirst().getExecutor().isPresent()) {
            // Flow is already dispatched to an executor, so call that executor to cancel the flow.
            this.apiGateway
                .callWithReferenceByUser(pair.getFirst(), ConnectorParams.CANCEL_ACTION, userId);
          } else {
            // Flow is still queued, need to finalize it and update the status in DB.
            ExecutionControllerUtils.finalizeFlow(this.executorLoader, this.alerterHolder, exFlow,
                "Cancelled before dispatching to executor", null);
          }
        } else {
          throw new ExecutorManagerException("Execution "
              + exFlow.getExecutionId() + " of flow " + exFlow.getFlowId()
              + " isn't running.");
        }
      }
    }
docs: If a flow is already dispatched to an executor, cancel by calling Executor. Else if it's still
  queued in DB, remove it from DB queue and finalize. {@inheritDoc}