@Override
    public TimingResult call() throws Exception {
      TimingResult result = new TimingResult();
      final int maxIterations = 10;
      int numAfterDone = 0;
      int resetCount = 0;
      // Keep trying until the rs is back up and we've gotten a put through
      while (numAfterDone < maxIterations) {
        long start = System.nanoTime();
        Span span = TraceUtil.getGlobalTracer().spanBuilder(getSpanName()).startSpan();
        try (Scope scope = span.makeCurrent()) {
          boolean actionResult = doAction();
          if (actionResult && future.isDone()) {
            numAfterDone++;
          }

          // the following Exceptions derive from DoNotRetryIOException. They are considered
          // fatal for the purpose of this test. If we see one of these, it means something is
          // broken and needs investigation. This is not the case for all children of DNRIOE.
          // Unfortunately, this is an explicit enumeration and will need periodically refreshed.
          // See HBASE-9655 for further discussion.
        } catch (AccessDeniedException e) {
          throw e;
        } catch (CoprocessorException e) {
          throw e;
        } catch (FatalConnectionException e) {
          throw e;
        } catch (InvalidFamilyOperationException e) {
          throw e;
        } catch (NamespaceExistException e) {
          throw e;
        } catch (NamespaceNotFoundException e) {
          throw e;
        } catch (NoSuchColumnFamilyException e) {
          throw e;
        } catch (TableExistsException e) {
          throw e;
        } catch (TableNotFoundException e) {
          throw e;
        } catch (RetriesExhaustedException e) {
          throw e;
          // Everything else is potentially recoverable on the application side. For instance, a CM
          // action kills the RS that hosted a scanner the client was using. Continued use of that
          // scanner should be terminated, but a new scanner can be created and the read attempted
          // again.
        } catch (Exception e) {
          resetCount++;
          if (resetCount < maxIterations) {
            LOG.info(
              "Non-fatal exception while running " + this.toString() + ". Resetting loop counter",
              e);
            numAfterDone = 0;
          } else {
            LOG.info("Too many unexpected Exceptions. Aborting.", e);
            throw e;
          }
        } finally {
          span.end();
        }
        result.addResult(System.nanoTime() - start, span);
      }
      return result;
    }
Base class for actions that need to record the time needed to recover from a failure.
hbase-it/src/test/java/org/apache/hadoop/hbase/mttr/IntegrationTestMTTR.java