base.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. from abc import ABCMeta, abstractmethod
  2. import logging
  3. import six
  4. class JobLookupError(KeyError):
  5. """Raised when the job store cannot find a job for update or removal."""
  6. def __init__(self, job_id):
  7. super(JobLookupError, self).__init__(u'No job by the id of %s was found' % job_id)
  8. class ConflictingIdError(KeyError):
  9. """Raised when the uniqueness of job IDs is being violated."""
  10. def __init__(self, job_id):
  11. super(ConflictingIdError, self).__init__(
  12. u'Job identifier (%s) conflicts with an existing job' % job_id)
  13. class TransientJobError(ValueError):
  14. """
  15. Raised when an attempt to add transient (with no func_ref) job to a persistent job store is
  16. detected.
  17. """
  18. def __init__(self, job_id):
  19. super(TransientJobError, self).__init__(
  20. u'Job (%s) cannot be added to this job store because a reference to the callable '
  21. u'could not be determined.' % job_id)
  22. class BaseJobStore(six.with_metaclass(ABCMeta)):
  23. """Abstract base class that defines the interface that every job store must implement."""
  24. _scheduler = None
  25. _alias = None
  26. _logger = logging.getLogger('apscheduler.jobstores')
  27. def start(self, scheduler, alias):
  28. """
  29. Called by the scheduler when the scheduler is being started or when the job store is being
  30. added to an already running scheduler.
  31. :param apscheduler.schedulers.base.BaseScheduler scheduler: the scheduler that is starting
  32. this job store
  33. :param str|unicode alias: alias of this job store as it was assigned to the scheduler
  34. """
  35. self._scheduler = scheduler
  36. self._alias = alias
  37. self._logger = logging.getLogger('apscheduler.jobstores.%s' % alias)
  38. def shutdown(self):
  39. """Frees any resources still bound to this job store."""
  40. def _fix_paused_jobs_sorting(self, jobs):
  41. for i, job in enumerate(jobs):
  42. if job.next_run_time is not None:
  43. if i > 0:
  44. paused_jobs = jobs[:i]
  45. del jobs[:i]
  46. jobs.extend(paused_jobs)
  47. break
  48. @abstractmethod
  49. def lookup_job(self, job_id):
  50. """
  51. Returns a specific job, or ``None`` if it isn't found..
  52. The job store is responsible for setting the ``scheduler`` and ``jobstore`` attributes of
  53. the returned job to point to the scheduler and itself, respectively.
  54. :param str|unicode job_id: identifier of the job
  55. :rtype: Job
  56. """
  57. @abstractmethod
  58. def get_due_jobs(self, now):
  59. """
  60. Returns the list of jobs that have ``next_run_time`` earlier or equal to ``now``.
  61. The returned jobs must be sorted by next run time (ascending).
  62. :param datetime.datetime now: the current (timezone aware) datetime
  63. :rtype: list[Job]
  64. """
  65. @abstractmethod
  66. def get_next_run_time(self):
  67. """
  68. Returns the earliest run time of all the jobs stored in this job store, or ``None`` if
  69. there are no active jobs.
  70. :rtype: datetime.datetime
  71. """
  72. @abstractmethod
  73. def get_all_jobs(self):
  74. """
  75. Returns a list of all jobs in this job store.
  76. The returned jobs should be sorted by next run time (ascending).
  77. Paused jobs (next_run_time == None) should be sorted last.
  78. The job store is responsible for setting the ``scheduler`` and ``jobstore`` attributes of
  79. the returned jobs to point to the scheduler and itself, respectively.
  80. :rtype: list[Job]
  81. """
  82. @abstractmethod
  83. def add_job(self, job):
  84. """
  85. Adds the given job to this store.
  86. :param Job job: the job to add
  87. :raises ConflictingIdError: if there is another job in this store with the same ID
  88. """
  89. @abstractmethod
  90. def update_job(self, job):
  91. """
  92. Replaces the job in the store with the given newer version.
  93. :param Job job: the job to update
  94. :raises JobLookupError: if the job does not exist
  95. """
  96. @abstractmethod
  97. def remove_job(self, job_id):
  98. """
  99. Removes the given job from this store.
  100. :param str|unicode job_id: identifier of the job
  101. :raises JobLookupError: if the job does not exist
  102. """
  103. @abstractmethod
  104. def remove_all_jobs(self):
  105. """Removes all jobs from this store."""
  106. def __repr__(self):
  107. return '<%s>' % self.__class__.__name__