From 1be408046b48a72e23e556cbbba3f50c64f5a29f Mon Sep 17 00:00:00 2001 From: Andy Shultz Date: Tue, 26 Oct 2021 13:35:01 -0400 Subject: [PATCH] feat: explain certificate delay seconds and make it overrideable this appears to be a throttling method on first glance but is instead an async task handling hack, explain it and then provide a way to override it for tight control of timing while regenerating multiple certs --- .../certificates/generation_handler.py | 24 ++++++++++++------- lms/djangoapps/certificates/tasks.py | 3 +++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/lms/djangoapps/certificates/generation_handler.py b/lms/djangoapps/certificates/generation_handler.py index a8b59b7cb9..d671a4ade0 100644 --- a/lms/djangoapps/certificates/generation_handler.py +++ b/lms/djangoapps/certificates/generation_handler.py @@ -27,7 +27,7 @@ from openedx.core.djangoapps.content.course_overviews.api import get_course_over log = logging.getLogger(__name__) -def generate_certificate_task(user, course_key, generation_mode=None): +def generate_certificate_task(user, course_key, generation_mode=None, delay_seconds=CERTIFICATE_DELAY_SECONDS): """ Create a task to generate a certificate for this user in this course run, if the user is eligible and a certificate can be generated. @@ -38,13 +38,16 @@ def generate_certificate_task(user, course_key, generation_mode=None): if is_on_certificate_allowlist(user, course_key): log.info(f'User {user.id} is on the allowlist for {course_key}. Attempt will be made to generate an allowlist ' f'certificate.') - return generate_allowlist_certificate_task(user, course_key, generation_mode) + return generate_allowlist_certificate_task(user, course_key, generation_mode=generation_mode, + delay_seconds=delay_seconds) log.info(f'Attempt will be made to generate course certificate for user {user.id} : {course_key}') - return _generate_regular_certificate_task(user, course_key, generation_mode) + return _generate_regular_certificate_task(user, course_key, generation_mode=generation_mode, + delay_seconds=delay_seconds) -def generate_allowlist_certificate_task(user, course_key, generation_mode=None): +def generate_allowlist_certificate_task(user, course_key, generation_mode=None, + delay_seconds=CERTIFICATE_DELAY_SECONDS): """ Create a task to generate an allowlist certificate for this user in this course run. """ @@ -52,7 +55,8 @@ def generate_allowlist_certificate_task(user, course_key, generation_mode=None): course_grade = _get_course_grade(user, course_key) if _can_generate_allowlist_certificate(user, course_key, enrollment_mode): return _generate_certificate_task(user=user, course_key=course_key, enrollment_mode=enrollment_mode, - course_grade=course_grade, generation_mode=generation_mode) + course_grade=course_grade, generation_mode=generation_mode, + delay_seconds=delay_seconds) status = _set_allowlist_cert_status(user, course_key, enrollment_mode, course_grade) if status is not None: @@ -61,7 +65,7 @@ def generate_allowlist_certificate_task(user, course_key, generation_mode=None): return False -def _generate_regular_certificate_task(user, course_key, generation_mode=None): +def _generate_regular_certificate_task(user, course_key, generation_mode=None, delay_seconds=CERTIFICATE_DELAY_SECONDS): """ Create a task to generate a regular (non-allowlist) certificate for this user in this course run, if the user is eligible and a certificate can be generated. @@ -70,7 +74,8 @@ def _generate_regular_certificate_task(user, course_key, generation_mode=None): course_grade = _get_course_grade(user, course_key) if _can_generate_regular_certificate(user, course_key, enrollment_mode, course_grade): return _generate_certificate_task(user=user, course_key=course_key, enrollment_mode=enrollment_mode, - course_grade=course_grade, generation_mode=generation_mode) + course_grade=course_grade, generation_mode=generation_mode, + delay_seconds=delay_seconds) status = _set_regular_cert_status(user, course_key, enrollment_mode, course_grade) if status is not None: @@ -79,7 +84,8 @@ def _generate_regular_certificate_task(user, course_key, generation_mode=None): return False -def _generate_certificate_task(user, course_key, enrollment_mode, course_grade, status=None, generation_mode=None): +def _generate_certificate_task(user, course_key, enrollment_mode, course_grade, status=None, generation_mode=None, + delay_seconds=CERTIFICATE_DELAY_SECONDS): """ Create a task to generate a certificate """ @@ -98,7 +104,7 @@ def _generate_certificate_task(user, course_key, enrollment_mode, course_grade, if generation_mode is not None: kwargs['generation_mode'] = generation_mode - generate_certificate.apply_async(countdown=CERTIFICATE_DELAY_SECONDS, kwargs=kwargs) + generate_certificate.apply_async(countdown=delay_seconds, kwargs=kwargs) return True diff --git a/lms/djangoapps/certificates/tasks.py b/lms/djangoapps/certificates/tasks.py index 184a353652..6d524352c3 100644 --- a/lms/djangoapps/certificates/tasks.py +++ b/lms/djangoapps/certificates/tasks.py @@ -15,6 +15,9 @@ from lms.djangoapps.certificates.generation import generate_course_certificate log = getLogger(__name__) User = get_user_model() + +# Certificate generation is delayed in case the caller is still completing their changes +# (for example a certificate regeneration reacting to a post save rather than post commit signal) CERTIFICATE_DELAY_SECONDS = 2