code: def fail_pipeline(self, e, dynamic_recover=False):
          
          # Take care of any active running subprocess
          sys.stdout.flush()
          self._terminate_running_subprocesses()
  
          if dynamic_recover:
              # job was terminated, not failed due to a bad process.
              # flag this run as recoverable.
              if len(self.locks) < 1:
                  # If there is no process locked, then recovery will be automatic.
                  print("No locked process. Dynamic recovery will be automatic.")
              # make a copy of self.locks to iterate over since we'll be clearing them as we go
              # set a recovery flag for each lock.
              for lock_file in self.locks[:]:
                  recover_file = self._recoverfile_from_lockfile(lock_file)
                  print("Setting dynamic recover file: {}".format(recover_file))
                  self._create_file(recover_file)
                  self.locks.remove(lock_file)
  
          # Produce cleanup script
          self._cleanup(dry_run=True)
  
          # Finally, set the status to failed and close out with a timestamp
          if not self._failed:  # and not self._completed:
              self.timestamp("### Pipeline failed at: ")
              total_time = datetime.timedelta(seconds=self.time_elapsed(self.starttime))
              print("Total time: " + str(total_time))
              self._set_status_flag(FAIL_FLAG)
  
          raise e
docs: If the pipeline does not complete, this function will stop the pipeline gracefully.
          It sets the status flag to failed and skips the normal success completion procedure.
  
          :param Exception e: Exception to raise.
          :param bool dynamic_recover: Whether to recover e.g. for job termination.