code: private void dispatch(final ExecutionReference reference, final ExecutableFlow exflow,
        final Executor choosenExecutor) throws ExecutorManagerException {
      exflow.setUpdateTime(System.currentTimeMillis());
  
      this.executorLoader.assignExecutor(choosenExecutor.getId(),
          exflow.getExecutionId());
      try {
        this.apiGateway.callWithExecutable(exflow, choosenExecutor,
            ConnectorParams.EXECUTE_ACTION);
      } catch (final ExecutorManagerException ex) {
        logger.error("Rolling back executor assignment for execution id:"
            + exflow.getExecutionId(), ex);
        this.executorLoader.unassignExecutor(exflow.getExecutionId());
        throw new ExecutorManagerException(ex);
      }
      reference.setExecutor(choosenExecutor);
  
      // move from flow to running flows
      this.runningExecutions.get().put(exflow.getExecutionId(), new Pair<>(reference, exflow));
      synchronized (this.runningExecutions.get()) {
        // Wake up RunningExecutionsUpdaterThread from wait() so that it will immediately check status
        // from executor(s). Normally flows will run at least some time and can't be cleaned up
        // immediately, so there will be another wait round (or many, actually), but for unit tests
        // this is significant to let them run quickly.
        this.runningExecutions.get().notifyAll();
      }
      synchronized (this) {
        // wake up all internal waiting threads, too
        this.notifyAll();
      }
  
      logger.info(String.format(
          "Successfully dispatched exec %d with error count %d",
          exflow.getExecutionId(), reference.getNumErrors()));
    }
docs: Calls executor to dispatch the flow, update db to assign the executor and in-memory state of
  executableFlow.