diff --git a/openedx/core/djangoapps/credentials/management/commands/notify_credentials.py b/openedx/core/djangoapps/credentials/management/commands/notify_credentials.py index 35c5b928cc..e4ee12bf01 100644 --- a/openedx/core/djangoapps/credentials/management/commands/notify_credentials.py +++ b/openedx/core/djangoapps/credentials/management/commands/notify_credentials.py @@ -21,6 +21,7 @@ from datetime import datetime, timedelta import dateutil.parser from django.contrib.auth import get_user_model from django.core.management.base import BaseCommand, CommandError +from MySQLdb import OperationalError from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey from pytz import UTC @@ -67,10 +68,24 @@ def paged_query(queryset, delay, page_size): if delay and page: time.sleep(delay) + index = 0 - for item in subquery.iterator(): - index += 1 - yield page_start + index, item + try: + for item in subquery.iterator(): + index += 1 + yield page_start + index, item + except OperationalError: + # When running the notify_credentials command locally there is an + # OperationalError thrown by MySQL when there are no more results + # available for the queryset iterator. This change catches that exception, + # checks state, and then logs according to that state. This code runs in + # production without issue. This changes allows for the code to be run + # locally without a separate code path. + if index == count: + log.info('OperationalError Exception caught, all known results processed in paged_query') + else: + log.warning('OperationalError Exception caught, it is possible some results were missed') + continue class Command(BaseCommand): @@ -246,6 +261,7 @@ class Command(BaseCommand): """ Run actual handler commands for the provided certs and grades. """ course_cert_info = {} + # First, do certs for i, cert in paged_query(certs, delay, page_size): if site_config and not site_config.has_org(cert.course_id.org):