From 8eef18710dbb39c6e5e2e9ff2ddbf0b916f5de2d Mon Sep 17 00:00:00 2001
From: Robert Raposa <rraposa@edx.org>
Date: Thu, 12 Nov 2020 23:19:42 -0500
Subject: [PATCH] set code_owner for celery tasks

ARCHBOM-1260

Co-authored-by: Tim McCormack <tmccormack@edx.org>
---
 cms/djangoapps/cms_user_tasks/tasks.py          |  2 ++
 cms/djangoapps/contentstore/tasks.py            | 10 ++++++++++
 common/djangoapps/entitlements/tasks.py         |  2 ++
 common/djangoapps/student/tasks.py              |  2 ++
 common/djangoapps/third_party_auth/tasks.py     |  2 ++
 .../lib/xmodule/xmodule/modulestore/django.py   |  2 ++
 lms/djangoapps/bulk_email/tasks.py              |  2 ++
 lms/djangoapps/certificates/tasks.py            |  2 ++
 lms/djangoapps/discussion/tasks.py              |  3 +++
 lms/djangoapps/email_marketing/tasks.py         |  5 +++++
 lms/djangoapps/gating/tasks.py                  |  2 ++
 lms/djangoapps/grades/tasks.py                  | 11 ++++++++++-
 lms/djangoapps/instructor_task/tasks.py         | 17 +++++++++++++++++
 lms/djangoapps/program_enrollments/tasks.py     |  2 ++
 lms/djangoapps/verify_student/tasks.py          |  3 +++
 openedx/core/djangoapps/bookmarks/tasks.py      |  2 ++
 openedx/core/djangoapps/ccxcon/tasks.py         |  2 ++
 .../content/course_overviews/tasks.py           |  2 ++
 openedx/core/djangoapps/coursegraph/tasks.py    |  2 ++
 .../djangoapps/credentials/tasks/v1/tasks.py    |  2 ++
 openedx/core/djangoapps/credit/tasks.py         |  2 ++
 openedx/core/djangoapps/heartbeat/tasks.py      |  2 ++
 openedx/core/djangoapps/programs/tasks.py       |  5 +++++
 openedx/core/djangoapps/schedules/tasks.py      |  6 +++++-
 .../djangoapps/verified_track_content/tasks.py  |  2 ++
 openedx/features/enterprise_support/tasks.py    |  2 ++
 requirements/edx/base.in                        |  2 +-
 requirements/edx/base.txt                       |  2 +-
 requirements/edx/development.txt                |  2 +-
 requirements/edx/testing.txt                    |  2 +-
 30 files changed, 98 insertions(+), 6 deletions(-)

diff --git a/cms/djangoapps/cms_user_tasks/tasks.py b/cms/djangoapps/cms_user_tasks/tasks.py
index 4f88fa104f2..f4b9d605ff4 100644
--- a/cms/djangoapps/cms_user_tasks/tasks.py
+++ b/cms/djangoapps/cms_user_tasks/tasks.py
@@ -9,6 +9,7 @@ from celery.task import task
 from celery.utils.log import get_task_logger
 from django.conf import settings
 from django.core import mail
+from edx_django_utils.monitoring import set_code_owner_attribute
 
 from common.djangoapps.edxmako.shortcuts import render_to_string
 from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
@@ -19,6 +20,7 @@ TASK_COMPLETE_EMAIL_TIMEOUT = 60
 
 
 @task(bind=True)
+@set_code_owner_attribute
 def send_task_complete_email(self, task_name, task_state_text, dest_addr, detail_url):
     """
     Sending an email to the users when an async task completes.
diff --git a/cms/djangoapps/contentstore/tasks.py b/cms/djangoapps/contentstore/tasks.py
index 37fae029260..5435986f6a4 100644
--- a/cms/djangoapps/contentstore/tasks.py
+++ b/cms/djangoapps/contentstore/tasks.py
@@ -22,6 +22,7 @@ from django.core.files import File
 from django.test import RequestFactory
 from django.utils.text import get_valid_filename
 from django.utils.translation import ugettext as _
+from edx_django_utils.monitoring import set_code_owner_attribute, set_code_owner_attribute_from_module
 from opaque_keys.edx.keys import CourseKey
 from opaque_keys.edx.locator import LibraryLocator
 from organizations.models import OrganizationCourse
@@ -83,6 +84,7 @@ def clone_instance(instance, field_values):
 
 
 @task()
+@set_code_owner_attribute
 def rerun_course(source_course_key_string, destination_course_key_string, user_id, fields=None):
     """
     Reruns a course in a new celery task.
@@ -169,6 +171,7 @@ def _parse_time(time_isoformat):
 
 
 @task(routing_key=settings.UPDATE_SEARCH_INDEX_JOB_QUEUE)
+@set_code_owner_attribute
 def update_search_index(course_id, triggered_time_isoformat):
     """ Updates course search index. """
     try:
@@ -193,6 +196,7 @@ def update_search_index(course_id, triggered_time_isoformat):
 
 
 @task()
+@set_code_owner_attribute
 def update_library_index(library_id, triggered_time_isoformat):
     """ Updates course search index. """
     try:
@@ -238,10 +242,13 @@ class CourseExportTask(UserTask):  # pylint: disable=abstract-method
 
 
 @task(base=CourseExportTask, bind=True)
+# Note: The decorator @set_code_owner_attribute could not be used because
+#   the implementation of this task breaks with any additional decorators.
 def export_olx(self, user_id, course_key_string, language):
     """
     Export a course or library to an OLX .tar.gz archive and prepare it for download.
     """
+    set_code_owner_attribute_from_module(__name__)
     courselike_key = CourseKey.from_string(course_key_string)
 
     try:
@@ -370,10 +377,13 @@ class CourseImportTask(UserTask):  # pylint: disable=abstract-method
 
 
 @task(base=CourseImportTask, bind=True)
+# Note: The decorator @set_code_owner_attribute could not be used because
+#   the implementation of this task breaks with any additional decorators.
 def import_olx(self, user_id, course_key_string, archive_path, archive_name, language):
     """
     Import a course or library from a provided OLX .tar.gz archive.
     """
+    set_code_owner_attribute_from_module(__name__)
     courselike_key = CourseKey.from_string(course_key_string)
     try:
         user = User.objects.get(pk=user_id)
diff --git a/common/djangoapps/entitlements/tasks.py b/common/djangoapps/entitlements/tasks.py
index 4262c6a3a81..ddc01ca572a 100644
--- a/common/djangoapps/entitlements/tasks.py
+++ b/common/djangoapps/entitlements/tasks.py
@@ -6,6 +6,7 @@ This file contains celery tasks for entitlements-related functionality.
 from celery import task
 from celery.utils.log import get_task_logger
 from django.conf import settings
+from edx_django_utils.monitoring import set_code_owner_attribute
 
 from common.djangoapps.entitlements.models import CourseEntitlement
 
@@ -25,6 +26,7 @@ MAX_RETRIES = 11
     routing_key=ROUTING_KEY,
     name='entitlements.expire_old_entitlements',
 )
+@set_code_owner_attribute
 def expire_old_entitlements(self, start, end, logid='...'):
     """
     This task is designed to be called to process a bundle of entitlements
diff --git a/common/djangoapps/student/tasks.py b/common/djangoapps/student/tasks.py
index 5b4cadf25cd..7e0fea47cff 100644
--- a/common/djangoapps/student/tasks.py
+++ b/common/djangoapps/student/tasks.py
@@ -13,6 +13,7 @@ from django.contrib.sites.models import Site
 from edx_ace import ace
 from edx_ace.errors import RecoverableChannelDeliveryError
 from edx_ace.message import Message
+from edx_django_utils.monitoring import set_code_owner_attribute
 from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
 from openedx.core.lib.celery.task_utils import emulate_http_request
 
@@ -20,6 +21,7 @@ log = logging.getLogger('edx.celery.task')
 
 
 @task(bind=True, name='student.send_activation_email')
+@set_code_owner_attribute
 def send_activation_email(self, msg_string, from_address=None):
     """
     Sending an activation email to the user.
diff --git a/common/djangoapps/third_party_auth/tasks.py b/common/djangoapps/third_party_auth/tasks.py
index 787c1fb5440..33ccd241d1a 100644
--- a/common/djangoapps/third_party_auth/tasks.py
+++ b/common/djangoapps/third_party_auth/tasks.py
@@ -12,6 +12,7 @@ import pytz
 import requests
 from celery.task import task
 from django.utils.timezone import now
+from edx_django_utils.monitoring import set_code_owner_attribute
 from lxml import etree
 from onelogin.saml2.utils import OneLogin_Saml2_Utils
 from requests import exceptions
@@ -31,6 +32,7 @@ class MetadataParseError(Exception):
 
 
 @task(name='third_party_auth.fetch_saml_metadata')
+@set_code_owner_attribute
 def fetch_saml_metadata():
     """
     Fetch and store/update the metadata of all IdPs
diff --git a/common/lib/xmodule/xmodule/modulestore/django.py b/common/lib/xmodule/xmodule/modulestore/django.py
index 3f65a538aca..d1a1d020250 100644
--- a/common/lib/xmodule/xmodule/modulestore/django.py
+++ b/common/lib/xmodule/xmodule/modulestore/django.py
@@ -139,6 +139,7 @@ class SignalHandler(object):
 
         from django.dispatch import receiver
         from celery.task import task
+        from edx_django_utils.monitoring import set_code_owner_attribute
         from xmodule.modulestore.django import modulestore, SignalHandler
 
         @receiver(SignalHandler.course_published)
@@ -146,6 +147,7 @@ class SignalHandler(object):
             do_my_expensive_update.delay(course_key)
 
         @task()
+        @set_code_owner_attribute
         def do_my_expensive_update(course_key):
             # ...
 
diff --git a/lms/djangoapps/bulk_email/tasks.py b/lms/djangoapps/bulk_email/tasks.py
index ef2b21aa3da..447482dbefb 100644
--- a/lms/djangoapps/bulk_email/tasks.py
+++ b/lms/djangoapps/bulk_email/tasks.py
@@ -37,6 +37,7 @@ from django.urls import reverse
 from django.utils import timezone
 from django.utils.translation import override as override_language
 from django.utils.translation import ugettext as _
+from edx_django_utils.monitoring import set_code_owner_attribute
 from markupsafe import escape
 from six import text_type
 
@@ -240,6 +241,7 @@ def perform_delegate_email_batches(entry_id, course_id, task_input, action_name)
 
 
 @task(default_retry_delay=settings.BULK_EMAIL_DEFAULT_RETRY_DELAY, max_retries=settings.BULK_EMAIL_MAX_RETRIES)
+@set_code_owner_attribute
 def send_course_email(entry_id, email_id, to_list, global_email_context, subtask_status_dict):
     """
     Sends an email to a list of recipients.
diff --git a/lms/djangoapps/certificates/tasks.py b/lms/djangoapps/certificates/tasks.py
index 12d6d60748f..c3561d5023e 100644
--- a/lms/djangoapps/certificates/tasks.py
+++ b/lms/djangoapps/certificates/tasks.py
@@ -8,6 +8,7 @@ from logging import getLogger
 from celery import task
 from celery_utils.persist_on_failure import LoggedPersistOnFailureTask
 from django.contrib.auth.models import User
+from edx_django_utils.monitoring import set_code_owner_attribute
 from opaque_keys.edx.keys import CourseKey
 
 from lms.djangoapps.verify_student.services import IDVerificationService
@@ -18,6 +19,7 @@ logger = getLogger(__name__)
 
 
 @task(base=LoggedPersistOnFailureTask, bind=True, default_retry_delay=30, max_retries=2)
+@set_code_owner_attribute
 def generate_certificate(self, **kwargs):
     """
     Generates a certificate for a single user.
diff --git a/lms/djangoapps/discussion/tasks.py b/lms/djangoapps/discussion/tasks.py
index 8c6c8d5a7a6..8c453e153cf 100644
--- a/lms/djangoapps/discussion/tasks.py
+++ b/lms/djangoapps/discussion/tasks.py
@@ -15,6 +15,7 @@ from django.contrib.sites.models import Site
 from edx_ace import ace
 from edx_ace.recipient import Recipient
 from edx_ace.utils import date
+from edx_django_utils.monitoring import set_code_owner_attribute
 from eventtracking import tracker
 from opaque_keys.edx.keys import CourseKey
 from six.moves.urllib.parse import urljoin
@@ -39,6 +40,7 @@ ROUTING_KEY = getattr(settings, 'ACE_ROUTING_KEY', None)
 
 
 @task(base=LoggedTask)
+@set_code_owner_attribute
 def update_discussions_map(context):
     """
     Updates the mapping between discussion_id to discussion block usage key
@@ -61,6 +63,7 @@ class ResponseNotification(BaseMessageType):
 
 
 @task(base=LoggedTask, routing_key=ROUTING_KEY)
+@set_code_owner_attribute
 def send_ace_message(context):
     context['course_id'] = CourseKey.from_string(context['course_id'])
 
diff --git a/lms/djangoapps/email_marketing/tasks.py b/lms/djangoapps/email_marketing/tasks.py
index 724b88e4f91..21051f43452 100644
--- a/lms/djangoapps/email_marketing/tasks.py
+++ b/lms/djangoapps/email_marketing/tasks.py
@@ -11,6 +11,7 @@ import six
 from celery import task
 from django.conf import settings
 from django.core.cache import cache
+from edx_django_utils.monitoring import set_code_owner_attribute
 from sailthru.sailthru_client import SailthruClient
 from sailthru.sailthru_error import SailthruClientError
 
@@ -22,6 +23,7 @@ ACE_ROUTING_KEY = getattr(settings, 'ACE_ROUTING_KEY', None)
 
 
 @task(bind=True, routing_key=ACE_ROUTING_KEY)
+@set_code_owner_attribute
 def get_email_cookies_via_sailthru(self, user_email, post_parms):
     """
     Adds/updates Sailthru cookie information for a new user.
@@ -62,6 +64,7 @@ def get_email_cookies_via_sailthru(self, user_email, post_parms):
 
 
 @task(bind=True, default_retry_delay=3600, max_retries=24, routing_key=ACE_ROUTING_KEY)
+@set_code_owner_attribute
 def update_user(self, sailthru_vars, email, site=None, new_user=False, activation=False):
     """
     Adds/updates Sailthru profile information for a user.
@@ -144,6 +147,7 @@ def is_default_site(site):
 
 
 @task(bind=True, default_retry_delay=3600, max_retries=24, routing_key=ACE_ROUTING_KEY)
+@set_code_owner_attribute
 def update_user_email(self, new_email, old_email):
     """
     Adds/updates Sailthru when a user email address is changed
@@ -304,6 +308,7 @@ def _retryable_sailthru_error(error):
 
 
 @task(bind=True, routing_key=ACE_ROUTING_KEY)
+@set_code_owner_attribute
 def update_course_enrollment(self, email, course_key, mode, site=None):
     """Adds/updates Sailthru when a user adds to cart/purchases/upgrades a course
          Args:
diff --git a/lms/djangoapps/gating/tasks.py b/lms/djangoapps/gating/tasks.py
index b550b114a66..5e43bcd2b31 100644
--- a/lms/djangoapps/gating/tasks.py
+++ b/lms/djangoapps/gating/tasks.py
@@ -8,6 +8,7 @@ import logging
 import six
 from celery import task
 from django.contrib.auth.models import User
+from edx_django_utils.monitoring import set_code_owner_attribute
 from opaque_keys.edx.keys import CourseKey, UsageKey
 
 from lms.djangoapps.gating import api as gating_api
@@ -18,6 +19,7 @@ log = logging.getLogger(__name__)
 
 
 @task()
+@set_code_owner_attribute
 def task_evaluate_subsection_completion_milestones(course_id, block_id, user_id):
     """
     Updates users' milestones related to completion of a subsection.
diff --git a/lms/djangoapps/grades/tasks.py b/lms/djangoapps/grades/tasks.py
index a2dafd3e6e3..2ccfdeb8af5 100644
--- a/lms/djangoapps/grades/tasks.py
+++ b/lms/djangoapps/grades/tasks.py
@@ -12,7 +12,11 @@ from django.conf import settings
 from django.contrib.auth.models import User
 from django.core.exceptions import ValidationError
 from django.db.utils import DatabaseError
-from edx_django_utils.monitoring import set_custom_attribute, set_custom_attributes_for_course_key
+from edx_django_utils.monitoring import (
+    set_code_owner_attribute,
+    set_custom_attribute,
+    set_custom_attributes_for_course_key
+)
 from opaque_keys.edx.keys import CourseKey, UsageKey
 from opaque_keys.edx.locator import CourseLocator
 from submissions import api as sub_api
@@ -49,6 +53,7 @@ SUBSECTION_GRADE_TIMEOUT_SECONDS = 300
 
 
 @task(base=LoggedPersistOnFailureTask, routing_key=settings.POLICY_CHANGE_GRADES_ROUTING_KEY)
+@set_code_owner_attribute
 def compute_all_grades_for_course(**kwargs):
     """
     Compute grades for all students in the specified course.
@@ -81,6 +86,7 @@ def compute_all_grades_for_course(**kwargs):
     time_limit=COURSE_GRADE_TIMEOUT_SECONDS,
     rate_limit=settings.POLICY_CHANGE_TASK_RATE_LIMIT,
 )
+@set_code_owner_attribute
 def compute_grades_for_course_v2(self, **kwargs):
     """
     Compute grades for a set of students in the specified course.
@@ -105,6 +111,7 @@ def compute_grades_for_course_v2(self, **kwargs):
 
 
 @task(base=LoggedPersistOnFailureTask)
+@set_code_owner_attribute
 def compute_grades_for_course(course_key, offset, batch_size, **kwargs):  # pylint: disable=unused-argument
     """
     Compute and save grades for a set of students in the specified course.
@@ -133,6 +140,7 @@ def compute_grades_for_course(course_key, offset, batch_size, **kwargs):  # pyli
     default_retry_delay=RETRY_DELAY_SECONDS,
     routing_key=settings.POLICY_CHANGE_GRADES_ROUTING_KEY
 )
+@set_code_owner_attribute
 def recalculate_course_and_subsection_grades_for_user(self, **kwargs):  # pylint: disable=unused-argument
     """
     Recalculates the course grade and all subsection grades
@@ -174,6 +182,7 @@ def recalculate_course_and_subsection_grades_for_user(self, **kwargs):  # pylint
     default_retry_delay=RETRY_DELAY_SECONDS,
     routing_key=settings.RECALCULATE_GRADES_ROUTING_KEY
 )
+@set_code_owner_attribute
 def recalculate_subsection_grade_v3(self, **kwargs):
     """
     Latest version of the recalculate_subsection_grade task.  See docstring
diff --git a/lms/djangoapps/instructor_task/tasks.py b/lms/djangoapps/instructor_task/tasks.py
index bf39d88e7d2..34d49748268 100644
--- a/lms/djangoapps/instructor_task/tasks.py
+++ b/lms/djangoapps/instructor_task/tasks.py
@@ -26,6 +26,7 @@ from functools import partial
 from celery import task
 from django.conf import settings
 from django.utils.translation import ugettext_noop
+from edx_django_utils.monitoring import set_code_owner_attribute
 
 from lms.djangoapps.bulk_email.tasks import perform_delegate_email_batches
 from lms.djangoapps.instructor_task.tasks_base import BaseInstructorTask
@@ -55,6 +56,7 @@ TASK_LOG = logging.getLogger('edx.celery.task')
 
 
 @task(base=BaseInstructorTask)
+@set_code_owner_attribute
 def rescore_problem(entry_id, xmodule_instance_args):
     """Rescores a problem in a course, for all students or one specific student.
 
@@ -82,6 +84,7 @@ def rescore_problem(entry_id, xmodule_instance_args):
 
 
 @task(base=BaseInstructorTask)
+@set_code_owner_attribute
 def override_problem_score(entry_id, xmodule_instance_args):
     """
     Overrides a specific learner's score on a problem.
@@ -95,6 +98,7 @@ def override_problem_score(entry_id, xmodule_instance_args):
 
 
 @task(base=BaseInstructorTask)
+@set_code_owner_attribute
 def reset_problem_attempts(entry_id, xmodule_instance_args):
     """Resets problem attempts to zero for a particular problem for all students in a course.
 
@@ -117,6 +121,7 @@ def reset_problem_attempts(entry_id, xmodule_instance_args):
 
 
 @task(base=BaseInstructorTask)
+@set_code_owner_attribute
 def delete_problem_state(entry_id, xmodule_instance_args):
     """Deletes problem state entirely for all students on a particular problem in a course.
 
@@ -139,6 +144,7 @@ def delete_problem_state(entry_id, xmodule_instance_args):
 
 
 @task(base=BaseInstructorTask)
+@set_code_owner_attribute
 def send_bulk_course_email(entry_id, _xmodule_instance_args):
     """Sends emails to recipients enrolled in a course.
 
@@ -164,6 +170,7 @@ def send_bulk_course_email(entry_id, _xmodule_instance_args):
     base=BaseInstructorTask,
     routing_key=settings.GRADES_DOWNLOAD_ROUTING_KEY,
 )
+@set_code_owner_attribute
 def calculate_problem_responses_csv(entry_id, xmodule_instance_args):
     """
     Compute student answers to a given problem and upload the CSV to
@@ -176,6 +183,7 @@ def calculate_problem_responses_csv(entry_id, xmodule_instance_args):
 
 
 @task(base=BaseInstructorTask, routing_key=settings.GRADES_DOWNLOAD_ROUTING_KEY)
+@set_code_owner_attribute
 def calculate_grades_csv(entry_id, xmodule_instance_args):
     """
     Grade a course and push the results to an S3 bucket for download.
@@ -192,6 +200,7 @@ def calculate_grades_csv(entry_id, xmodule_instance_args):
 
 
 @task(base=BaseInstructorTask, routing_key=settings.GRADES_DOWNLOAD_ROUTING_KEY)
+@set_code_owner_attribute
 def calculate_problem_grade_report(entry_id, xmodule_instance_args):
     """
     Generate a CSV for a course containing all students' problem
@@ -209,6 +218,7 @@ def calculate_problem_grade_report(entry_id, xmodule_instance_args):
 
 
 @task(base=BaseInstructorTask)
+@set_code_owner_attribute
 def calculate_students_features_csv(entry_id, xmodule_instance_args):
     """
     Compute student profile information for a course and upload the
@@ -221,6 +231,7 @@ def calculate_students_features_csv(entry_id, xmodule_instance_args):
 
 
 @task(base=BaseInstructorTask)
+@set_code_owner_attribute
 def course_survey_report_csv(entry_id, xmodule_instance_args):
     """
     Compute the survey report for a course and upload the
@@ -233,6 +244,7 @@ def course_survey_report_csv(entry_id, xmodule_instance_args):
 
 
 @task(base=BaseInstructorTask)
+@set_code_owner_attribute
 def proctored_exam_results_csv(entry_id, xmodule_instance_args):
     """
     Compute proctored exam results report for a course and upload the
@@ -244,6 +256,7 @@ def proctored_exam_results_csv(entry_id, xmodule_instance_args):
 
 
 @task(base=BaseInstructorTask)
+@set_code_owner_attribute
 def calculate_may_enroll_csv(entry_id, xmodule_instance_args):
     """
     Compute information about invited students who have not enrolled
@@ -257,6 +270,7 @@ def calculate_may_enroll_csv(entry_id, xmodule_instance_args):
 
 
 @task(base=BaseInstructorTask, routing_key=settings.GRADES_DOWNLOAD_ROUTING_KEY)
+@set_code_owner_attribute
 def generate_certificates(entry_id, xmodule_instance_args):
     """
     Grade students and generate certificates.
@@ -273,6 +287,7 @@ def generate_certificates(entry_id, xmodule_instance_args):
 
 
 @task(base=BaseInstructorTask)
+@set_code_owner_attribute
 def cohort_students(entry_id, xmodule_instance_args):
     """
     Cohort students in bulk, and upload the results.
@@ -285,6 +300,7 @@ def cohort_students(entry_id, xmodule_instance_args):
 
 
 @task(base=BaseInstructorTask)
+@set_code_owner_attribute
 def export_ora2_data(entry_id, xmodule_instance_args):
     """
     Generate a CSV of ora2 responses and push it to S3.
@@ -295,6 +311,7 @@ def export_ora2_data(entry_id, xmodule_instance_args):
 
 
 @task(base=BaseInstructorTask)
+@set_code_owner_attribute
 def export_ora2_submission_files(entry_id, xmodule_instance_args):
     """
     Download all submission files, generate csv downloads list,
diff --git a/lms/djangoapps/program_enrollments/tasks.py b/lms/djangoapps/program_enrollments/tasks.py
index e454491e331..46f356d8c00 100644
--- a/lms/djangoapps/program_enrollments/tasks.py
+++ b/lms/djangoapps/program_enrollments/tasks.py
@@ -7,6 +7,7 @@ from datetime import timedelta
 from celery import task
 from celery_utils.logged_task import LoggedTask
 from django.utils import timezone
+from edx_django_utils.monitoring import set_code_owner_attribute
 
 from lms.djangoapps.program_enrollments.models import ProgramCourseEnrollment, ProgramEnrollment
 
@@ -14,6 +15,7 @@ log = logging.getLogger(__name__)
 
 
 @task(base=LoggedTask)
+@set_code_owner_attribute
 def expire_waiting_enrollments(expiration_days):
     """
     Remove all ProgramEnrollments and related ProgramCourseEnrollments for
diff --git a/lms/djangoapps/verify_student/tasks.py b/lms/djangoapps/verify_student/tasks.py
index 9ced28e260b..aca08deac0a 100644
--- a/lms/djangoapps/verify_student/tasks.py
+++ b/lms/djangoapps/verify_student/tasks.py
@@ -11,6 +11,7 @@ from celery import Task, task
 from celery.states import FAILURE
 from django.conf import settings
 from django.core.mail import EmailMessage
+from edx_django_utils.monitoring import set_code_owner_attribute
 
 from common.djangoapps.edxmako.shortcuts import render_to_string
 from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
@@ -74,6 +75,7 @@ class BaseSoftwareSecureTask(Task):
 
 
 @task(routing_key=ACE_ROUTING_KEY)
+@set_code_owner_attribute
 def send_verification_status_email(context):
     """
     Spins a task to send verification status email to the learner
@@ -101,6 +103,7 @@ def send_verification_status_email(context):
     max_retries=settings.SOFTWARE_SECURE_RETRY_MAX_ATTEMPTS,
     routing_key=SOFTWARE_SECURE_VERIFICATION_ROUTING_KEY,
 )
+@set_code_owner_attribute
 def send_request_to_ss_for_user(self, user_verification_id, copy_id_photo_from):
     """
     Assembles a submission to Software Secure.
diff --git a/openedx/core/djangoapps/bookmarks/tasks.py b/openedx/core/djangoapps/bookmarks/tasks.py
index 69b959b8ad0..179261852b9 100644
--- a/openedx/core/djangoapps/bookmarks/tasks.py
+++ b/openedx/core/djangoapps/bookmarks/tasks.py
@@ -8,6 +8,7 @@ import logging
 import six
 from celery.task import task
 from django.db import transaction
+from edx_django_utils.monitoring import set_code_owner_attribute
 from opaque_keys.edx.keys import CourseKey
 
 from xmodule.modulestore.django import modulestore
@@ -145,6 +146,7 @@ def _update_xblocks_cache(course_key):
 
 
 @task(name=u'openedx.core.djangoapps.bookmarks.tasks.update_xblocks_cache')
+@set_code_owner_attribute
 def update_xblocks_cache(course_id):
     """
     Update the XBlocks cache for a course.
diff --git a/openedx/core/djangoapps/ccxcon/tasks.py b/openedx/core/djangoapps/ccxcon/tasks.py
index 437aded7e7c..13d137320f2 100644
--- a/openedx/core/djangoapps/ccxcon/tasks.py
+++ b/openedx/core/djangoapps/ccxcon/tasks.py
@@ -5,6 +5,7 @@ This file contains celery tasks for ccxcon
 
 from celery.task import task
 from celery.utils.log import get_task_logger
+from edx_django_utils.monitoring import set_code_owner_attribute
 from opaque_keys.edx.keys import CourseKey
 from requests.exceptions import ConnectionError, HTTPError, RequestException, TooManyRedirects
 
@@ -14,6 +15,7 @@ log = get_task_logger(__name__)
 
 
 @task(name='openedx.core.djangoapps.ccxcon.tasks.update_ccxcon')
+@set_code_owner_attribute
 def update_ccxcon(course_id, cur_retry=0):
     """
     Pass through function to update course information on CCXCon.
diff --git a/openedx/core/djangoapps/content/course_overviews/tasks.py b/openedx/core/djangoapps/content/course_overviews/tasks.py
index d21e9dcbb6d..fd9e0e93870 100644
--- a/openedx/core/djangoapps/content/course_overviews/tasks.py
+++ b/openedx/core/djangoapps/content/course_overviews/tasks.py
@@ -6,6 +6,7 @@ import six
 from celery import task
 from celery_utils.persist_on_failure import LoggedPersistOnFailureTask
 from django.conf import settings
+from edx_django_utils.monitoring import set_code_owner_attribute
 from opaque_keys.edx.keys import CourseKey
 from six.moves import range  # pylint: disable=ungrouped-imports
 
@@ -59,6 +60,7 @@ def enqueue_async_course_overview_update_tasks(
 
 
 @task(base=LoggedPersistOnFailureTask)
+@set_code_owner_attribute
 def async_course_overview_update(*args, **kwargs):
     course_keys = [CourseKey.from_string(arg) for arg in args]
     CourseOverview.update_select_courses(course_keys, force_update=kwargs['force_update'])
diff --git a/openedx/core/djangoapps/coursegraph/tasks.py b/openedx/core/djangoapps/coursegraph/tasks.py
index 4e32a2d53ad..b9c2ec0894b 100644
--- a/openedx/core/djangoapps/coursegraph/tasks.py
+++ b/openedx/core/djangoapps/coursegraph/tasks.py
@@ -10,6 +10,7 @@ from celery import task
 from django.conf import settings
 from django.utils import six, timezone
 from edx_django_utils.cache import RequestCache
+from edx_django_utils.monitoring import set_code_owner_attribute
 from opaque_keys.edx.keys import CourseKey
 from py2neo import Graph, Node, Relationship, authenticate, NodeSelector
 from py2neo.compat import integer, string
@@ -247,6 +248,7 @@ def should_dump_course(course_key, graph):
 
 
 @task(routing_key=settings.COURSEGRAPH_JOB_QUEUE)
+@set_code_owner_attribute
 def dump_course_to_neo4j(course_key_string, credentials):
     """
     Serializes a course and writes it to neo4j.
diff --git a/openedx/core/djangoapps/credentials/tasks/v1/tasks.py b/openedx/core/djangoapps/credentials/tasks/v1/tasks.py
index 5b3e72fc89f..040aaba75bd 100644
--- a/openedx/core/djangoapps/credentials/tasks/v1/tasks.py
+++ b/openedx/core/djangoapps/credentials/tasks/v1/tasks.py
@@ -7,6 +7,7 @@ from celery import task
 from celery.utils.log import get_task_logger
 from django.conf import settings
 from django.contrib.auth.models import User
+from edx_django_utils.monitoring import set_code_owner_attribute
 from opaque_keys.edx.keys import CourseKey
 
 from openedx.core.djangoapps.credentials.utils import get_credentials_api_client
@@ -26,6 +27,7 @@ MAX_RETRIES = 11
 
 
 @task(bind=True, ignore_result=True, routing_key=ROUTING_KEY)
+@set_code_owner_attribute
 def send_grade_to_credentials(self, username, course_run_key, verified, letter_grade, percent_grade):
     """ Celery task to notify the Credentials IDA of a grade change via POST. """
     logger.info(u'Running task send_grade_to_credentials for username %s and course %s', username, course_run_key)
diff --git a/openedx/core/djangoapps/credit/tasks.py b/openedx/core/djangoapps/credit/tasks.py
index 2443337ed65..f1e78e8f323 100644
--- a/openedx/core/djangoapps/credit/tasks.py
+++ b/openedx/core/djangoapps/credit/tasks.py
@@ -7,6 +7,7 @@ import six
 from celery import task
 from celery.utils.log import get_task_logger
 from django.conf import settings
+from edx_django_utils.monitoring import set_code_owner_attribute
 from opaque_keys import InvalidKeyError
 from opaque_keys.edx.keys import CourseKey, UsageKey
 
@@ -20,6 +21,7 @@ LOGGER = get_task_logger(__name__)
 
 
 @task(default_retry_delay=settings.CREDIT_TASK_DEFAULT_RETRY_DELAY, max_retries=settings.CREDIT_TASK_MAX_RETRIES)
+@set_code_owner_attribute
 def update_credit_course_requirements(course_id):
     """
     Updates course requirements table for a course.
diff --git a/openedx/core/djangoapps/heartbeat/tasks.py b/openedx/core/djangoapps/heartbeat/tasks.py
index dca2849b51b..7dd184b760f 100644
--- a/openedx/core/djangoapps/heartbeat/tasks.py
+++ b/openedx/core/djangoapps/heartbeat/tasks.py
@@ -5,8 +5,10 @@ A trivial task for health checks
 
 from celery.task import task
 from django.conf import settings
+from edx_django_utils.monitoring import set_code_owner_attribute
 
 
 @task(routing_key=settings.HEARTBEAT_CELERY_ROUTING_KEY)
+@set_code_owner_attribute
 def sample_task():
     return True
diff --git a/openedx/core/djangoapps/programs/tasks.py b/openedx/core/djangoapps/programs/tasks.py
index fb3c68ba2b3..8d0853f1e65 100644
--- a/openedx/core/djangoapps/programs/tasks.py
+++ b/openedx/core/djangoapps/programs/tasks.py
@@ -9,6 +9,7 @@ from celery.utils.log import get_task_logger
 from django.conf import settings
 from django.contrib.auth.models import User
 from django.contrib.sites.models import Site
+from edx_django_utils.monitoring import set_code_owner_attribute
 from edx_rest_api_client import exceptions
 from opaque_keys.edx.keys import CourseKey
 
@@ -124,6 +125,7 @@ def award_program_certificate(client, username, program_uuid, visible_date):
 
 
 @task(bind=True, ignore_result=True, routing_key=PROGRAM_CERTIFICATES_ROUTING_KEY)
+@set_code_owner_attribute
 def award_program_certificates(self, username):
     """
     This task is designed to be called whenever a student's completion status
@@ -286,6 +288,7 @@ def post_course_certificate(client, username, certificate, visible_date):
 
 
 @task(bind=True, ignore_result=True, routing_key=ROUTING_KEY)
+@set_code_owner_attribute
 def award_course_certificate(self, username, course_run_key):
     """
     This task is designed to be called whenever a student GeneratedCertificate is updated.
@@ -400,6 +403,7 @@ def revoke_program_certificate(client, username, program_uuid):
 
 
 @task(bind=True, ignore_result=True, routing_key=PROGRAM_CERTIFICATES_ROUTING_KEY)
+@set_code_owner_attribute
 def revoke_program_certificates(self, username, course_key):
     """
     This task is designed to be called whenever a student's course certificate is
@@ -523,6 +527,7 @@ def revoke_program_certificates(self, username, course_key):
 
 
 @task(bind=True, ignore_result=True, routing_key=PROGRAM_CERTIFICATES_ROUTING_KEY)
+@set_code_owner_attribute
 def update_certificate_visible_date_on_course_update(self, course_key):
     """
     This task is designed to be called whenever a course is updated with
diff --git a/openedx/core/djangoapps/schedules/tasks.py b/openedx/core/djangoapps/schedules/tasks.py
index 4aa119cc3d5..33c5cd94198 100644
--- a/openedx/core/djangoapps/schedules/tasks.py
+++ b/openedx/core/djangoapps/schedules/tasks.py
@@ -16,7 +16,7 @@ from django.db.utils import DatabaseError
 from edx_ace import ace
 from edx_ace.message import Message
 from edx_ace.utils.date import deserialize, serialize
-from edx_django_utils.monitoring import set_custom_attribute
+from edx_django_utils.monitoring import set_code_owner_attribute, set_custom_attribute
 from eventtracking import tracker
 from opaque_keys.edx.keys import CourseKey
 
@@ -43,6 +43,7 @@ COURSE_NEXT_SECTION_UPDATE_LOG_PREFIX = 'Course Next Section Update'
 
 
 @task(base=LoggedPersistOnFailureTask, bind=True, default_retry_delay=30)
+@set_code_owner_attribute
 def update_course_schedules(self, **kwargs):
     course_key = CourseKey.from_string(kwargs['course_id'])
     new_start_date = deserialize(kwargs['new_start_date_str'])
@@ -144,6 +145,7 @@ class BinnedScheduleMessageBaseTask(ScheduleMessageBaseTask):
 
 
 @task(base=LoggedTask, ignore_result=True, routing_key=ROUTING_KEY)
+@set_code_owner_attribute
 def _recurring_nudge_schedule_send(site_id, msg_str):
     _schedule_send(
         msg_str,
@@ -154,6 +156,7 @@ def _recurring_nudge_schedule_send(site_id, msg_str):
 
 
 @task(base=LoggedTask, ignore_result=True, routing_key=ROUTING_KEY)
+@set_code_owner_attribute
 def _upgrade_reminder_schedule_send(site_id, msg_str):
     _schedule_send(
         msg_str,
@@ -164,6 +167,7 @@ def _upgrade_reminder_schedule_send(site_id, msg_str):
 
 
 @task(base=LoggedTask, ignore_result=True, routing_key=ROUTING_KEY)
+@set_code_owner_attribute
 def _course_update_schedule_send(site_id, msg_str):
     _schedule_send(
         msg_str,
diff --git a/openedx/core/djangoapps/verified_track_content/tasks.py b/openedx/core/djangoapps/verified_track_content/tasks.py
index 2335743df21..b4a9082c67e 100644
--- a/openedx/core/djangoapps/verified_track_content/tasks.py
+++ b/openedx/core/djangoapps/verified_track_content/tasks.py
@@ -8,6 +8,7 @@ import six
 from celery.task import task
 from celery.utils.log import get_task_logger
 from django.contrib.auth.models import User
+from edx_django_utils.monitoring import set_code_owner_attribute
 from opaque_keys.edx.keys import CourseKey
 
 from openedx.core.djangoapps.course_groups.cohorts import add_user_to_cohort, get_cohort, get_cohort_by_name
@@ -17,6 +18,7 @@ LOGGER = get_task_logger(__name__)
 
 
 @task(bind=True, default_retry_delay=60, max_retries=2)
+@set_code_owner_attribute
 def sync_cohort_with_mode(self, course_id, user_id, verified_cohort_name, default_cohort_name):
     """
     If the learner's mode does not match their assigned cohort, move the learner into the correct cohort.
diff --git a/openedx/features/enterprise_support/tasks.py b/openedx/features/enterprise_support/tasks.py
index 875dc6bb91a..b553183c92c 100644
--- a/openedx/features/enterprise_support/tasks.py
+++ b/openedx/features/enterprise_support/tasks.py
@@ -6,6 +6,7 @@ Tasks for Enterprise.
 import logging
 
 from celery import task
+from edx_django_utils.monitoring import set_code_owner_attribute
 
 from enterprise.models import EnterpriseCourseEnrollment
 from openedx.features.enterprise_support.utils import clear_data_consent_share_cache
@@ -14,6 +15,7 @@ log = logging.getLogger('edx.celery.task')
 
 
 @task(name=u'openedx.features.enterprise_support.tasks.clear_enterprise_customer_data_consent_share_cache')
+@set_code_owner_attribute
 def clear_enterprise_customer_data_consent_share_cache(enterprise_customer_uuid):
     """
         clears data_sharing_consent_needed cache for whole enterprise
diff --git a/requirements/edx/base.in b/requirements/edx/base.in
index 7ee2854dd61..f02354430f1 100644
--- a/requirements/edx/base.in
+++ b/requirements/edx/base.in
@@ -78,7 +78,7 @@ edx-celeryutils
 edx-completion
 edx-django-release-util             # Release utils for the edx release pipeline
 edx-django-sites-extensions
-edx-django-utils>=3.8.0             # Utilities for cache, monitoring, and plugins; 3.8.0+ for set_custom_attribute method
+edx-django-utils>=3.12.0            # Utilities for cache, monitoring, and plugins; 3.12.0+ for set_code_owner_attribute method
 edx-drf-extensions
 edx-enterprise
 edx-milestones
diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt
index cecc6b2a9c0..4d2400b3b1b 100644
--- a/requirements/edx/base.txt
+++ b/requirements/edx/base.txt
@@ -96,7 +96,7 @@ edx-celeryutils==0.5.2    # via -r requirements/edx/base.in, super-csv
 edx-completion==3.2.5     # via -c requirements/edx/../constraints.txt, -r requirements/edx/base.in
 edx-django-release-util==0.4.4  # via -r requirements/edx/base.in
 edx-django-sites-extensions==2.5.1  # via -r requirements/edx/base.in
-edx-django-utils==3.11.0  # via -r requirements/edx/base.in, django-config-models, edx-drf-extensions, edx-enterprise, edx-rest-api-client, edx-toggles, edx-when
+edx-django-utils==3.12.0  # via -r requirements/edx/base.in, django-config-models, edx-drf-extensions, edx-enterprise, edx-rest-api-client, edx-toggles, edx-when
 edx-drf-extensions==6.2.0  # via -r requirements/edx/base.in, edx-completion, edx-enterprise, edx-organizations, edx-proctoring, edx-rbac, edx-when, edxval
 edx-enterprise==3.12.0    # via -c requirements/edx/../constraints.txt, -r requirements/edx/base.in
 edx-i18n-tools==0.5.3     # via ora2
diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt
index a6c46815fac..9c1ef2a80f1 100644
--- a/requirements/edx/development.txt
+++ b/requirements/edx/development.txt
@@ -107,7 +107,7 @@ edx-celeryutils==0.5.2    # via -r requirements/edx/testing.txt, super-csv
 edx-completion==3.2.5     # via -c requirements/edx/../constraints.txt, -r requirements/edx/testing.txt
 edx-django-release-util==0.4.4  # via -r requirements/edx/testing.txt
 edx-django-sites-extensions==2.5.1  # via -r requirements/edx/testing.txt
-edx-django-utils==3.11.0  # via -r requirements/edx/testing.txt, django-config-models, edx-drf-extensions, edx-enterprise, edx-rest-api-client, edx-toggles, edx-when
+edx-django-utils==3.12.0  # via -r requirements/edx/testing.txt, django-config-models, edx-drf-extensions, edx-enterprise, edx-rest-api-client, edx-toggles, edx-when
 edx-drf-extensions==6.2.0  # via -r requirements/edx/testing.txt, edx-completion, edx-enterprise, edx-organizations, edx-proctoring, edx-rbac, edx-when, edxval
 edx-enterprise==3.12.0    # via -c requirements/edx/../constraints.txt, -r requirements/edx/testing.txt
 edx-i18n-tools==0.5.3     # via -r requirements/edx/testing.txt, ora2
diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt
index 3035386e1ef..06520dac577 100644
--- a/requirements/edx/testing.txt
+++ b/requirements/edx/testing.txt
@@ -104,7 +104,7 @@ edx-celeryutils==0.5.2    # via -r requirements/edx/base.txt, super-csv
 edx-completion==3.2.5     # via -c requirements/edx/../constraints.txt, -r requirements/edx/base.txt
 edx-django-release-util==0.4.4  # via -r requirements/edx/base.txt
 edx-django-sites-extensions==2.5.1  # via -r requirements/edx/base.txt
-edx-django-utils==3.11.0  # via -r requirements/edx/base.txt, django-config-models, edx-drf-extensions, edx-enterprise, edx-rest-api-client, edx-toggles, edx-when
+edx-django-utils==3.12.0  # via -r requirements/edx/base.txt, django-config-models, edx-drf-extensions, edx-enterprise, edx-rest-api-client, edx-toggles, edx-when
 edx-drf-extensions==6.2.0  # via -r requirements/edx/base.txt, edx-completion, edx-enterprise, edx-organizations, edx-proctoring, edx-rbac, edx-when, edxval
 edx-enterprise==3.12.0    # via -c requirements/edx/../constraints.txt, -r requirements/edx/base.txt
 edx-i18n-tools==0.5.3     # via -r requirements/edx/base.txt, -r requirements/edx/testing.in, ora2
-- 
GitLab