class_docstr: The ORM class representing Job stored in the database.
  
  Jobs are processing items with state and duration that aren't task instances.
  For instance a BackfillJob is a collection of task instance runs,
  but should have its own state, start and end time.
class_docstr_tok: ["The","ORM","class","representing","Job","stored","in","the","database",".","Jobs","are","processing","items","with","state","and","duration","that","are","n't","task","instances",".","For","instance","a","BackfillJob","is","a","collection","of","task","instance","runs",",","but","should","have","its","own","state",",","start","and","end","time","."]
docstr: Update the job's entry in the database with the latest_heartbeat timestamp.
  
  This allows for the job to be killed externally and allows the system
  to monitor what is actually active.  For instance, an old heartbeat
  for SchedulerJob would mean something is wrong.  This also allows for
  any job to be killed externally, regardless of who is running it or on
  which machine it is running.
  
  Note that if your heart rate is set to 60 seconds and you call this
  method after 10 seconds of processing since the last heartbeat, it
  will sleep 50 seconds to complete the 60 seconds and keep a steady
  heart rate. If you go over 60 seconds before calling it, it won't
  sleep at all.
  
  :param heartbeat_callback: Callback that will be run when the heartbeat is recorded in the Job
  :param session to use for saving the job
docstr_tok: ["Update","the","job","'s","entry","in","the","database","with","the","latest_heartbeat","timestamp",".","This","allows","for","the","job","to","be","killed","externally","and","allows","the","system","to","monitor","what","is","actually","active",".","For","instance",",","an","old","heartbeat","for","SchedulerJob","would","mean","something","is","wrong",".","This","also","allows","for","any","job","to","be","killed","externally",",","regardless","of","who","is","running","it","or","on","which","machine","it","is","running",".","Note","that","if","your","heart","rate","is","set","to","60","seconds","and","you","call","this","method","after","10","seconds","of","processing","since","the","last","heartbeat",",","it","will","sleep","50","seconds","to","complete","the","60","seconds","and","keep","a","steady","heart","rate",".","If","you","go","over","60","seconds","before","calling","it",",","it","won't","sleep","at","all",".",":","param","heartbeat_callback",":","Callback","that","will","be","run","when","the","heartbeat","is","recorded","in","the","Job",":","param","session","to","use","for","saving","the","job"]
code: def heartbeat(
      self,
      heartbeat_callback: Callable[[Session], None],
      session: Session = NEW_SESSION,
  ) -> None:
      """
      Update the job's entry in the database with the latest_heartbeat timestamp.
  
      This allows for the job to be killed externally and allows the system
      to monitor what is actually active.  For instance, an old heartbeat
      for SchedulerJob would mean something is wrong.  This also allows for
      any job to be killed externally, regardless of who is running it or on
      which machine it is running.
  
      Note that if your heart rate is set to 60 seconds and you call this
      method after 10 seconds of processing since the last heartbeat, it
      will sleep 50 seconds to complete the 60 seconds and keep a steady
      heart rate. If you go over 60 seconds before calling it, it won't
      sleep at all.
  
      :param heartbeat_callback: Callback that will be run when the heartbeat is recorded in the Job
      :param session to use for saving the job
      """
      previous_heartbeat = self.latest_heartbeat
  
      try:
          # This will cause it to load from the db
          self._merge_from(Job._fetch_from_db(self, session))
          previous_heartbeat = self.latest_heartbeat
  
          if self.state == JobState.RESTARTING:
              self.kill()
  
          # Figure out how long to sleep for
          sleep_for = 0
          if self.latest_heartbeat:
              seconds_remaining = (
                  self.heartrate
                  - (
                      timezone.utcnow() - self.latest_heartbeat
                  ).total_seconds()
              )
              sleep_for = max(0, seconds_remaining)
          sleep(sleep_for)
  
          job = Job._update_heartbeat(job=self, session=session)
          self._merge_from(job)
  
          # At this point, the DB has updated.
          previous_heartbeat = self.latest_heartbeat
  
          heartbeat_callback(session)
          self.log.debug("[heartbeat]")
      except OperationalError:
          Stats.incr(
              convert_camel_to_snake(self.__class__.__name__)
              + "_heartbeat_failure",
              1,
              1,
          )
          if not self.heartbeat_failed:
              self.log.exception(
                  "%s heartbeat got an exception",
                  self.__class__.__name__,
              )
              self.heartbeat_failed = True
          if self.is_alive():
              self.log.error(
                  "%s heartbeat failed with error. Scheduler may go into unhealthy state",
                  self.__class__.__name__,
              )
          else:
              self.log.error(
                  "%s heartbeat failed with error. Scheduler is in unhealthy state",
                  self.__class__.__name__,
              )
          # We didn't manage to heartbeat, so make sure that the timestamp isn't updated
          self.latest_heartbeat = previous_heartbeat
  
imports: from __future__ import annotations
  from functools import cached_property
  from time import sleep
  from typing import TYPE_CHECKING, Callable, NoReturn
  from sqlalchemy import Column, Index, Integer, String, case, select
  from sqlalchemy.exc import OperationalError
  from sqlalchemy.orm import backref, foreign, relationship
  from sqlalchemy.orm.session import make_transient
  from airflow.api_internal.internal_api_call import internal_api_call
  from airflow.configuration import conf
  from airflow.exceptions import AirflowException
  from airflow.executors.executor_loader import ExecutorLoader
  from airflow.listeners.listener import get_listener_manager
  from airflow.models.base import ID_LEN, Base
  from airflow.serialization.pydantic.job import JobPydantic
  from airflow.stats import Stats
  from airflow.utils import timezone
  from airflow.utils.helpers import convert_camel_to_snake
  from airflow.utils.log.logging_mixin import LoggingMixin
  from airflow.utils.net import get_hostname
  from airflow.utils.platform import getuser
  from airflow.utils.session import NEW_SESSION, provide_session
  from airflow.utils.sqlalchemy import UtcDateTime
  from airflow.utils.state import JobState
label_desc: Use image node_id 7 for calling the Job obj's underlying member method code with example usage: obj.heartbeat(heartbeat_callback, session) without return types