code: private void notifyStoppedOrFailed(Throwable runException) {
          final Throwable stopException = this.stopException.get();
          if (runException == null) {
              // If runTask did not fail with an exception, see if we have a general stopException.
              runException = stopException;
          }
  
          if (runException instanceof CancellationException) {
              // CancellationExceptions are expected if we are shutting down the service; If this was the real
              // cause why runTask failed, then the service did not actually fail, so do not report a bogus exception.
              runException = null;
          }
  
          if (runException == null) {
              // Normal shutdown.
              notifyStopped();
          } else {
              if (stopException != null && stopException != runException) {
                  // We have both a stopException and a runTask exception. Since the stopException came first, that is the
                  // one we need to fail with, so add the runTask exception as suppressed.
                  stopException.addSuppressed(runException);
                  runException = stopException;
              }
  
              // Shutdown caused by some failure.
              notifyFailed(runException);
  
          }
  
          log.info("{}: Stopped.", this.traceObjectId);
      }
docs: Notifies the AbstractService to enter the TERMINATED or FAILED state, based on the current state of the Service
  and the given Exception.
  
  @param runException (Optional) A Throwable that indicates the failure cause of runTask.