From 7b41683d1c85dddc0586e562150c60c3cf21c30d Mon Sep 17 00:00:00 2001 From: jcass77 Date: Tue, 11 Aug 2020 10:28:48 +0200 Subject: [PATCH] fix(events): Fix mapping of event listener codes to APScheduler event classes. --- django_apscheduler/jobstores.py | 69 +++++++++++++++++++-------------- docs/changelog.md | 7 ++++ tests/test_jobstores.py | 22 ++++------- 3 files changed, 55 insertions(+), 43 deletions(-) diff --git a/django_apscheduler/jobstores.py b/django_apscheduler/jobstores.py index f8b7bc8..2d020a8 100644 --- a/django_apscheduler/jobstores.py +++ b/django_apscheduler/jobstores.py @@ -42,26 +42,41 @@ def handle_submission_event(cls, event: JobSubmissionEvent): :param event: JobExecutionEvent instance :return: DjangoJobExecution ID """ - if event.code != events.EVENT_JOB_SUBMITTED: + if event.code == events.EVENT_JOB_SUBMITTED: + # Start logging a new job execution + job_execution = DjangoJobExecution.atomic_update_or_create( + cls.lock, + event.job_id, + event.scheduled_run_times[0], + DjangoJobExecution.SENT, + ) + elif event.code == events.EVENT_JOB_MAX_INSTANCES: + status = DjangoJobExecution.MAX_INSTANCES + + exception = ( + f"Execution of job '{event.job_id}' skipped: maximum number of running " + f"instances reached!" + ) + + job_execution = DjangoJobExecution.atomic_update_or_create( + cls.lock, + event.job_id, + event.scheduled_run_times[0], + status, + exception=exception, + ) + else: raise NotImplementedError( f"Don't know how to handle JobSubmissionEvent '{event.code}'. Expected " - f"'{events.EVENT_JOB_SUBMITTED}'." + f"one of '{[events.EVENT_JOB_SUBMITTED, events.EVENT_JOB_MAX_INSTANCES]}'." ) - # Start logging a new job execution - job_execution = DjangoJobExecution.atomic_update_or_create( - cls.lock, - event.job_id, - event.scheduled_run_times[0], - DjangoJobExecution.SENT, - ) - return job_execution.id @classmethod def handle_execution_event(cls, event: JobExecutionEvent) -> int: """ - Store successful job execution status in the database. + Store "successful" job execution status in the database. :param event: JobExecutionEvent instance :return: DjangoJobExecution ID @@ -80,7 +95,7 @@ def handle_execution_event(cls, event: JobExecutionEvent) -> int: @classmethod def handle_error_event(cls, event: JobExecutionEvent) -> int: """ - Store failed job execution status in the database. + Store "failed" job execution status in the database. :param event: JobExecutionEvent instance :return: DjangoJobExecution ID @@ -103,19 +118,10 @@ def handle_error_event(cls, event: JobExecutionEvent) -> int: traceback=traceback, ) - elif event.code in [events.EVENT_JOB_MAX_INSTANCES, events.EVENT_JOB_MISSED]: + elif event.code == events.EVENT_JOB_MISSED: # Job execution will not have been logged yet - do so now - if event.code == events.EVENT_JOB_MAX_INSTANCES: - status = DjangoJobExecution.MAX_INSTANCES - - exception = ( - f"Execution of job '{event.job_id}' skipped: maximum number of running " - f"instances reached!" - ) - - else: - status = DjangoJobExecution.MISSED - exception = f"Run time of job '{event.job_id}' was missed!" + status = DjangoJobExecution.MISSED + exception = f"Run time of job '{event.job_id}' was missed!" job_execution = DjangoJobExecution.atomic_update_or_create( cls.lock, @@ -134,8 +140,16 @@ def handle_error_event(cls, event: JobExecutionEvent) -> int: return job_execution.id def register_event_listeners(self): + """ + Register various event listeners. + + See: https://github.com/agronholm/apscheduler/blob/master/docs/modules/events.rst for details on which event + class is used for each event code. + + """ self._scheduler.add_listener( - self.handle_submission_event, events.EVENT_JOB_SUBMITTED + self.handle_submission_event, + events.EVENT_JOB_SUBMITTED | events.EVENT_JOB_MAX_INSTANCES, ) self._scheduler.add_listener( @@ -143,10 +157,7 @@ def register_event_listeners(self): ) self._scheduler.add_listener( - self.handle_error_event, - events.EVENT_JOB_MAX_INSTANCES - | events.EVENT_JOB_ERROR - | events.EVENT_JOB_MISSED, + self.handle_error_event, events.EVENT_JOB_ERROR | events.EVENT_JOB_MISSED, ) diff --git a/docs/changelog.md b/docs/changelog.md index 81c25af..92c29c5 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -3,6 +3,13 @@ This changelog is used to track all major changes to django_apscheduler. +## v0.4.2 (UNRELEASED) + +**Fixes** + +- Fix mapping of event listener APScheduler codes to event classes (Fixes [#98](https://github.com/jarekwg/django-apscheduler/issues/98)). + + ## v0.4.1 (2020-07-09) **Fixes** diff --git a/tests/test_jobstores.py b/tests/test_jobstores.py index 40fa608..38a37ea 100644 --- a/tests/test_jobstores.py +++ b/tests/test_jobstores.py @@ -32,13 +32,14 @@ def test_handle_submission_event_not_supported_raises_exception(self, jobstore): jobstore.handle_submission_event(event) @pytest.mark.django_db + @pytest.mark.parametrize( + "event_code", [events.EVENT_JOB_SUBMITTED, events.EVENT_JOB_MAX_INSTANCES,], + ) def test_handle_submission_event_creates_job_execution( - self, jobstore, create_add_job + self, event_code, jobstore, create_add_job ): job = create_add_job(jobstore, dummy_job, datetime(2016, 5, 3)) - event = JobSubmissionEvent( - events.EVENT_JOB_SUBMITTED, job.id, jobstore, [timezone.now()] - ) + event = JobSubmissionEvent(event_code, job.id, jobstore, [timezone.now()]) jobstore.handle_submission_event(event) assert DjangoJobExecution.objects.filter(job_id=event.job_id).exists() @@ -75,12 +76,7 @@ def test_handle_error_event_not_supported_raises_exception(self, jobstore): @pytest.mark.django_db @pytest.mark.parametrize( - "event_code", - [ - events.EVENT_JOB_MAX_INSTANCES, - events.EVENT_JOB_MISSED, - events.EVENT_JOB_ERROR, - ], + "event_code", [events.EVENT_JOB_MISSED, events.EVENT_JOB_ERROR,], ) def test_handle_error_event_creates_job_execution( self, jobstore, create_add_job, event_code @@ -113,11 +109,9 @@ def test_register_event_listeners_registers_listeners(self, jobstore): assert all( event_code in registered_event_codes for event_code in [ - events.EVENT_JOB_SUBMITTED, + events.EVENT_JOB_SUBMITTED | events.EVENT_JOB_MAX_INSTANCES, events.EVENT_JOB_EXECUTED, - events.EVENT_JOB_MAX_INSTANCES - | events.EVENT_JOB_ERROR - | events.EVENT_JOB_MISSED, + events.EVENT_JOB_ERROR | events.EVENT_JOB_MISSED, ] )