docs: def RunJob(self, job):
      """Does the actual work of the Cron, if the job is due to run.
  
      Args:
        job: The cronjob rdfvalue that should be run. Must be leased.
  
      Returns:
        A boolean indicating if this cron job was started or not. False may
        be returned when the threadpool is already full.
  
      Raises:
        LockError: if the object is not locked.
        ValueError: If the job argument is invalid.
      """
      if not job.leased_until:
        raise LockError("CronJob must be leased for Run() to be called.")
      if job.leased_until < rdfvalue.RDFDatetime.Now():
        raise LockError("CronJob lease expired for %s." % job.cron_job_id)
  
      logging.info("Starting cron job: %s", job.cron_job_id)
  
      if job.args.action_type == job.args.ActionType.SYSTEM_CRON_ACTION:
        cls_name = job.args.system_cron_action.job_class_name
        job_cls = registry.SystemCronJobRegistry.CronJobClassByName(cls_name)
        name = "%s runner" % cls_name
      elif job.args.action_type == job.args.ActionType.HUNT_CRON_ACTION:
        job_cls = registry.CronJobRegistry.CronJobClassByName("RunHunt")
        name = "Hunt runner"
      else:
        raise ValueError(
            "CronJob %s doesn't have a valid args type set." % job.cron_job_id)
  
      run_state = rdf_cronjobs.CronJobRun(
          cron_job_id=job.cron_job_id, status="RUNNING")
      run_state.GenerateRunId()
  
      run_obj = job_cls(run_state, job)
      wait_for_start_event, signal_event, wait_for_write_event = (
          threading.Event(), threading.Event(), threading.Event())
      try:
        self._GetThreadPool().AddTask(
            target=run_obj.StartRun,
            args=(wait_for_start_event, signal_event, wait_for_write_event),
            name=name,
            blocking=False,
            inline=False)
        if not wait_for_start_event.wait(TASK_STARTUP_WAIT):
          logging.error("Cron job run task for %s is too slow to start.",
                        job.cron_job_id)
          # Most likely the thread pool is full and the task is sitting on the
          # queue. Make sure we don't put more things on the queue by returning
          # False.
          return False
  
        # We know that the cron job task has started, unblock it by setting
        # the signal event. If signal_event is not set (this happens if the
        # task sits on a ThreadPool's queue doing nothing, see the
        # if-statement above) the task will just be a no-op when ThreadPool
        # finally gets to it. This way we can ensure that we can safely return
        # the lease and let another worker schedule the same job.
        signal_event.set()
  
        wait_for_write_event.wait(TASK_STARTUP_WAIT)
  
        return True
      except threadpool.Full:
        return False