@Override
  protected Procedure<MasterProcedureEnv>[] execute(MasterProcedureEnv env)
    throws ProcedureYieldException, ProcedureSuspendedException, InterruptedException {
    RegionStateNode regionNode = getRegionNode(env);
    try {
      switch (state) {
        case REGION_REMOTE_PROCEDURE_DISPATCH: {
          // The code which wakes us up also needs to lock the RSN so here we do not need to
          // synchronize on the event.
          ProcedureEvent<?> event = regionNode.getProcedureEvent();
          try {
            env.getRemoteDispatcher().addOperationToNode(targetServer, this);
          } catch (FailedRemoteDispatchException e) {
            LOG.warn("Can not add remote operation {} for region {} to server {}, this usually "
              + "because the server is alread dead, give up and mark the procedure as complete, "
              + "the parent procedure will take care of this.", this, region, targetServer, e);
            unattach(env);
            return null;
          }
          event.suspend();
          event.suspendIfNotReady(this);
          throw new ProcedureSuspendedException();
        }
        case REGION_REMOTE_PROCEDURE_REPORT_SUCCEED:
          if (
            ProcedureFutureUtil.checkFuture(this, this::getFuture, this::setFuture,
              () -> unattach(env))
          ) {
            return null;
          }
          ProcedureFutureUtil.suspendIfNecessary(this, this::setFuture,
            env.getAssignmentManager().persistToMeta(regionNode), env, () -> unattach(env));
          return null;
        case REGION_REMOTE_PROCEDURE_DISPATCH_FAIL:
          // the remote call is failed so we do not need to change the region state, just return.
          unattach(env);
          return null;
        case REGION_REMOTE_PROCEDURE_SERVER_CRASH:
          if (
            ProcedureFutureUtil.checkFuture(this, this::getFuture, this::setFuture,
              () -> unattach(env))
          ) {
            return null;
          }
          ProcedureFutureUtil.suspendIfNecessary(this, this::setFuture,
            env.getAssignmentManager().regionClosedAbnormally(regionNode), env,
            () -> unattach(env));
          return null;
        default:
          throw new IllegalStateException("Unknown state: " + state);
      }
    } catch (IOException e) {
      if (retryCounter == null) {
        retryCounter = ProcedureUtil.createRetryCounter(env.getMasterConfiguration());
      }
      long backoff = retryCounter.getBackoffTimeAndIncrementAttempts();
      LOG.warn("Failed updating meta, suspend {}secs {}; {};", backoff / 1000, this, regionNode, e);
      throw suspend(Math.toIntExact(backoff), true);
    }
  }
The base class for the remote procedures used to open/close a region.
<p/>
Notice that here we do not care about the result of the remote call, if the remote call is
finished, either succeeded or not, we will always finish the procedure. The parent procedure
should take care of the result and try to reschedule if the result is not good.
hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/RegionRemoteProcedureBase.java