diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml deleted file mode 100644 index 2a971adae360..000000000000 --- a/.github/workflows/semgrep.yml +++ /dev/null @@ -1,47 +0,0 @@ -# Finds code problems by structural pattern matching. -# -# New rules can be added to test_root/semgrep/ and they should be picked up -# automatically. See https://semgrep.dev/docs/ for documentation. - -name: Semgrep code quality - -on: - pull_request: - merge_group: - push: - branches: - - master - -jobs: - run_semgrep: - name: Semgrep analysis - runs-on: "${{ matrix.os }}" - strategy: - matrix: - os: ["ubuntu-latest"] - python-version: - - "3.12" - - steps: - - uses: actions/checkout@v7 - with: - fetch-depth: 1 - - - uses: actions/setup-python@v6 - with: - python-version: "${{ matrix.python-version }}" - - - name: Install semgrep - run: | - make pre-requirements - pip-sync requirements/edx/semgrep.txt - - - name: Run semgrep - env: - # Peg this to some reasonable value so that semgrep's rewrapping - # of messages doesn't break up lines in an unpredictable manner: - # https://github.com/returntocorp/semgrep/issues/8608 - COLUMNS: 80 - run: | - semgrep scan --config test_root/semgrep/ --error --quiet \ - -- lms cms common openedx diff --git a/Makefile b/Makefile index 98931cb608d2..e97c3c2fd9c4 100644 --- a/Makefile +++ b/Makefile @@ -96,7 +96,6 @@ REQ_FILES = \ requirements/edx/testing \ requirements/edx/assets \ requirements/edx/development \ - requirements/edx/semgrep \ scripts/xblock/requirements \ scripts/user_retirement/requirements/base \ scripts/user_retirement/requirements/testing \ diff --git a/cms/djangoapps/cms_user_tasks/tasks.py b/cms/djangoapps/cms_user_tasks/tasks.py index 0efc852e22c6..7be7762f3fd6 100644 --- a/cms/djangoapps/cms_user_tasks/tasks.py +++ b/cms/djangoapps/cms_user_tasks/tasks.py @@ -9,7 +9,6 @@ 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 @@ -20,7 +19,6 @@ @shared_task(bind=True) -@set_code_owner_attribute def send_task_complete_email(self, task_name, task_state_text, dest_addr, detail_url, olx_validation_text=None, is_course_optimizer_task=False): """ diff --git a/cms/djangoapps/contentstore/tasks.py b/cms/djangoapps/contentstore/tasks.py index d16e941b09e1..f5227a480a23 100644 --- a/cms/djangoapps/contentstore/tasks.py +++ b/cms/djangoapps/contentstore/tasks.py @@ -26,8 +26,6 @@ from django.test import RequestFactory from django.utils.text import get_valid_filename from edx_django_utils.monitoring import ( - set_code_owner_attribute, - set_code_owner_attribute_from_module, set_custom_attribute, set_custom_attributes_for_course_key, ) @@ -166,7 +164,6 @@ def clone_instance(instance, field_values): @shared_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. @@ -262,7 +259,6 @@ def _parse_time(time_isoformat): @shared_task -@set_code_owner_attribute def update_search_index(course_id, triggered_time_isoformat): """ Updates course search index. """ try: @@ -293,7 +289,6 @@ def update_search_index(course_id, triggered_time_isoformat): @shared_task -@set_code_owner_attribute def update_library_index(library_id, triggered_time_isoformat): """ Updates course search index. """ try: @@ -307,7 +302,6 @@ def update_library_index(library_id, triggered_time_isoformat): @shared_task -@set_code_owner_attribute def update_special_exams_and_publish(course_key_str): """ Registers special exams for a given course and calls publishing flow. @@ -368,13 +362,11 @@ def generate_name(cls, arguments_dict): @shared_task(base=CourseExportTask, bind=True) -# Note: The decorator @set_code_owner_attribute cannot be used here because the UserTaskMixin # does stack inspection and can't handle 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: @@ -546,14 +538,12 @@ def sync_discussion_settings(course_key, user): @shared_task(base=CourseImportTask, bind=True) -# Note: The decorator @set_code_owner_attribute cannot be used here because the UserTaskMixin # does stack inspection and can't handle additional decorators. # pylint: disable=too-many-statements 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 or .zip archive. """ - set_code_owner_attribute_from_module(__name__) current_step = 'Unpacking' courselike_key = CourseKey.from_string(course_key_string) set_custom_attributes_for_course_key(courselike_key) @@ -789,7 +779,6 @@ def read_chunk(): @shared_task -@set_code_owner_attribute def update_all_outlines_from_modulestore_task(): """ Celery task that creates multiple celery tasks - one per learning_sequence course outline @@ -816,7 +805,6 @@ def update_all_outlines_from_modulestore_task(): @shared_task -@set_code_owner_attribute def update_outline_from_modulestore_task(course_key_str: str): """ Celery task that creates a learning_sequence course outline. @@ -961,7 +949,6 @@ def _get_users_by_access_level(v1_library_key): @shared_task(time_limit=30) -@set_code_owner_attribute def delete_v1_library(v1_library_key_string): """ Delete a v1 library index by key string. @@ -987,6 +974,146 @@ def delete_v1_library(v1_library_key_string): } +@shared_task(time_limit=30) +def validate_all_library_source_blocks_ids_for_course(course_key_string, v1_to_v2_lib_map): + """Search a Modulestore for all library source blocks in a course by querying mongo. + replace all source_library_ids with the corresponding v2 value from the map + """ + course_id = CourseKey.from_string(course_key_string) + store = modulestore() + with store.bulk_operations(course_id): + visited = [] + for branch in [ModuleStoreEnum.BranchName.draft, ModuleStoreEnum.BranchName.published]: + blocks = store.get_items( + course_id.for_branch(branch), + settings={'source_library_id': {'$exists': True}} + ) + for xblock in blocks: + if xblock.source_library_id not in v1_to_v2_lib_map.values(): + # pylint: disable=broad-except + raise Exception( + f'{xblock.source_library_id} in {course_id} is not found in mapping. Validation failed' + ) + visited.append(xblock.source_library_id) + # return sucess + return visited + + +@shared_task(time_limit=30) +def replace_all_library_source_blocks_ids_for_course(course_key_string, v1_to_v2_lib_map): # pylint: disable=useless-return + """Search a Modulestore for all library source blocks in a course by querying mongo. + replace all source_library_ids with the corresponding v2 value from the map. + + This will trigger a publish on the course for every published library source block. + """ + store = modulestore() + course_id = CourseKey.from_string(course_key_string) + + with store.bulk_operations(course_id): + #for branch in [ModuleStoreEnum.BranchName.draft, ModuleStoreEnum.BranchName.published]: + draft_blocks, published_blocks = [ + store.get_items( + course_id.for_branch(branch), + settings={'source_library_id': {'$exists': True}} + ) + for branch in [ModuleStoreEnum.BranchName.draft, ModuleStoreEnum.BranchName.published] + ] + + published_dict = {block.location: block for block in published_blocks} + + for draft_library_source_block in draft_blocks: + try: + new_source_id = str(v1_to_v2_lib_map[draft_library_source_block.source_library_id]) + except KeyError: + #skip invalid keys + LOGGER.error( + 'Key %s not found in mapping. Skipping block for course %s', + str({draft_library_source_block.source_library_id}), + str(course_id) + ) + continue + + # The publsihed branch should be updated as well as the draft branch + # This way, if authors "discard changes," they won't be reverted back to the V1 lib. + # However, we also don't want to publish the draft branch. + try: + if published_dict[draft_library_source_block.location] is not None: + #temporarily set the published version to be the draft & publish it. + temp = published_dict[draft_library_source_block.location] + temp.source_library_id = new_source_id + store.update_item(temp, None) + store.publish(temp.location, None) + draft_library_source_block.source_library_id = new_source_id + store.update_item(draft_library_source_block, None) + except KeyError: + #Warn, but just update the draft block if no published block for draft block. + LOGGER.warning( + 'No matching published block for draft block %s', + str(draft_library_source_block.location) + ) + draft_library_source_block.source_library_id = new_source_id + store.update_item(draft_library_source_block, None) + # return success + return + + +@shared_task(time_limit=30) +def undo_all_library_source_blocks_ids_for_course(course_key_string, v1_to_v2_lib_map): # pylint: disable=useless-return + """Search a Modulestore for all library source blocks in a course by querying mongo. + replace all source_library_ids with the corresponding v1 value from the inverted map. + This is exists to undo changes made previously. + """ + course_id = CourseKey.from_string(course_key_string) + + v2_to_v1_lib_map = {v: k for k, v in v1_to_v2_lib_map.items()} + + store = modulestore() + draft_blocks, published_blocks = [ + store.get_items( + course_id.for_branch(branch), + settings={'source_library_id': {'$exists': True}} + ) + for branch in [ModuleStoreEnum.BranchName.draft, ModuleStoreEnum.BranchName.published] + ] + + published_dict = {block.location: block for block in published_blocks} + + for draft_library_source_block in draft_blocks: + try: + new_source_id = str(v2_to_v1_lib_map[draft_library_source_block.source_library_id]) + except KeyError: + #skip invalid keys + LOGGER.error( + 'Key %s not found in mapping. Skipping block for course %s', + str({draft_library_source_block.source_library_id}), + str(course_id) + ) + continue + + # The publsihed branch should be updated as well as the draft branch + # This way, if authors "discard changes," they won't be reverted back to the V1 lib. + # However, we also don't want to publish the draft branch. + try: + if published_dict[draft_library_source_block.location] is not None: + #temporarily set the published version to be the draft & publish it. + temp = published_dict[draft_library_source_block.location] + temp.source_library_id = new_source_id + store.update_item(temp, None) + store.publish(temp.location, None) + draft_library_source_block.source_library_id = new_source_id + store.update_item(draft_library_source_block, None) + except KeyError: + #Warn, but just update the draft block if no published block for draft block. + LOGGER.warning( + 'No matching published block for draft block %s', + str(draft_library_source_block.location) + ) + draft_library_source_block.source_library_id = new_source_id + store.update_item(draft_library_source_block, None) + # return success + return + + class CourseLinkCheckTask(UserTask): # pylint: disable=abstract-method """ Base class for course link check tasks. @@ -1021,13 +1148,11 @@ def generate_name(cls, arguments_dict): @shared_task(base=CourseLinkCheckTask, bind=True) -# Note: The decorator @set_code_owner_attribute cannot be used here because the UserTaskMixin # does stack inspection and can't handle additional decorators. def check_broken_links(self, user_id, course_key_string, language): """ Checks for broken links in a course and store the results in a file. """ - set_code_owner_attribute_from_module(__name__) return _check_broken_links(self, user_id, course_key_string, language) @@ -1495,7 +1620,6 @@ def _write_broken_links_to_file(broken_or_locked_urls, broken_links_file): @shared_task -@set_code_owner_attribute def handle_create_xblock_upstream_link(usage_key): """ Create upstream link for a single xblock. @@ -1523,7 +1647,6 @@ def handle_create_xblock_upstream_link(usage_key): @shared_task -@set_code_owner_attribute def handle_update_xblock_upstream_link(usage_key): """ Update upstream link for a single xblock. @@ -1540,7 +1663,6 @@ def handle_update_xblock_upstream_link(usage_key): @shared_task -@set_code_owner_attribute def create_or_update_upstream_links( course_key_str: str, force: bool = False, @@ -1581,7 +1703,6 @@ def create_or_update_upstream_links( @shared_task -@set_code_owner_attribute def handle_unlink_upstream_block(upstream_usage_key_string: str) -> None: """ Handle updates needed to downstream blocks when the upstream link is severed. @@ -1601,7 +1722,6 @@ def handle_unlink_upstream_block(upstream_usage_key_string: str) -> None: @shared_task -@set_code_owner_attribute def handle_unlink_upstream_container(upstream_container_key_string: str) -> None: """ Handle updates needed to downstream blocks when the upstream link is severed. @@ -1658,7 +1778,6 @@ def update_course_rerun_links( """ Updates course links to point to the latest re-run. """ - set_code_owner_attribute_from_module(__name__) return _update_course_rerun_links( self, user_id, course_id, action, data, language ) @@ -2214,7 +2333,6 @@ def migrate_course_legacy_library_blocks_to_item_bank( leaving migrated blocks as drafts. """ ensure_cms("Legacy library content references may only be executed in CMS") - set_code_owner_attribute_from_module(__name__) _cancel_old_tasks(course_key, self.status.user, [self.status.task_id]) try: key = CourseKey.from_string(course_key) diff --git a/cms/djangoapps/export_course_metadata/tasks.py b/cms/djangoapps/export_course_metadata/tasks.py index c95b91adde28..5477e873a4bf 100644 --- a/cms/djangoapps/export_course_metadata/tasks.py +++ b/cms/djangoapps/export_course_metadata/tasks.py @@ -6,7 +6,6 @@ from celery import shared_task from django.core.files.base import ContentFile -from edx_django_utils.monitoring import set_code_owner_attribute from opaque_keys.edx.keys import CourseKey from openedx.core.djangoapps.schedules.content_highlights import get_all_course_highlights @@ -15,7 +14,6 @@ @shared_task(bind=True) -@set_code_owner_attribute def export_course_metadata_task(self, course_key_string): # pylint: disable=unused-argument """ Export course metadata diff --git a/cms/djangoapps/modulestore_migrator/tasks.py b/cms/djangoapps/modulestore_migrator/tasks.py index 3426302c3c10..a4b7c503aa94 100644 --- a/cms/djangoapps/modulestore_migrator/tasks.py +++ b/cms/djangoapps/modulestore_migrator/tasks.py @@ -17,7 +17,6 @@ from django.db import transaction from django.utils.text import slugify from django.utils.translation import gettext_lazy as _ -from edx_django_utils.monitoring import set_code_owner_attribute_from_module from lxml import etree from lxml.etree import _ElementTree as XmlTree from opaque_keys import InvalidKeyError @@ -490,7 +489,6 @@ def _set_migrations_to_fail(source_data_list: list[_MigrationSourceData]): @shared_task(base=_BulkMigrationTask, bind=True) -# Note: The decorator @set_code_owner_attribute cannot be used here because the UserTaskMixin # does stack inspection and can't handle additional decorators. def bulk_migrate_from_modulestore( self: _BulkMigrationTask, @@ -548,7 +546,6 @@ def bulk_migrate_from_modulestore( # This is a large function, but breaking it up futher would probably not # make it any easier to understand. - set_code_owner_attribute_from_module(__name__) status: UserTaskStatus = self.status # Validating input diff --git a/common/djangoapps/entitlements/tasks.py b/common/djangoapps/entitlements/tasks.py index 2ce2399ef847..63d70fcf6e6f 100644 --- a/common/djangoapps/entitlements/tasks.py +++ b/common/djangoapps/entitlements/tasks.py @@ -7,7 +7,6 @@ from celery.utils.log import get_task_logger from django.conf import settings # pylint: disable=unused-import # noqa: F401 from django.contrib.auth import get_user_model -from edx_django_utils.monitoring import set_code_owner_attribute from common.djangoapps.entitlements.models import CourseEntitlement, CourseEntitlementSupportDetail @@ -24,7 +23,6 @@ @shared_task(bind=True, ignore_result=True) -@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 @@ -69,7 +67,6 @@ def expire_old_entitlements(self, start, end, logid='...'): @shared_task(bind=True) -@set_code_owner_attribute def expire_and_create_entitlements(self, entitlement_ids, support_username): """ Expire entitlements older than one year. diff --git a/common/djangoapps/student/tasks.py b/common/djangoapps/student/tasks.py index cf95d56a99db..a366d295859d 100644 --- a/common/djangoapps/student/tasks.py +++ b/common/djangoapps/student/tasks.py @@ -6,7 +6,6 @@ from celery import shared_task from django.conf import settings from django.contrib.auth import get_user_model -from edx_django_utils.monitoring import set_code_owner_attribute from opaque_keys.edx.keys import CourseKey from common.djangoapps.course_modes.models import CourseMode @@ -28,7 +27,6 @@ @shared_task(bind=True, ignore_result=True) -@set_code_owner_attribute def send_course_enrollment_email( self, user_id, course_id, course_title, short_description, course_ended, pacing_type, track_mode ): diff --git a/common/djangoapps/third_party_auth/tasks.py b/common/djangoapps/third_party_auth/tasks.py index ad942814ae56..704375717c96 100644 --- a/common/djangoapps/third_party_auth/tasks.py +++ b/common/djangoapps/third_party_auth/tasks.py @@ -8,7 +8,6 @@ import requests from celery import shared_task from django.core.exceptions import ObjectDoesNotExist -from edx_django_utils.monitoring import set_code_owner_attribute from lxml import etree from requests import exceptions from social_django.models import UserSocialAuth @@ -28,7 +27,6 @@ @shared_task -@set_code_owner_attribute def fetch_saml_metadata(): """ Fetch and store/update the metadata of all IdPs @@ -139,7 +137,6 @@ def fetch_saml_metadata(): @shared_task -@set_code_owner_attribute def update_saml_users_social_auth_uid(reader, slug): """ Update the UserSocialAuth UID for users based on a CSV reader input. diff --git a/lms/djangoapps/bulk_email/tasks.py b/lms/djangoapps/bulk_email/tasks.py index ff3108fbe0e3..06c7c9786876 100644 --- a/lms/djangoapps/bulk_email/tasks.py +++ b/lms/djangoapps/bulk_email/tasks.py @@ -25,7 +25,6 @@ from django.utils import timezone from django.utils.translation import gettext as _ from django.utils.translation import override as override_language -from edx_django_utils.monitoring import set_code_owner_attribute from eventtracking import tracker from markupsafe import escape @@ -232,7 +231,6 @@ def _create_send_email_subtask(to_list, initial_subtask_status): @shared_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/ccx/tasks.py b/lms/djangoapps/ccx/tasks.py index 5b9fd9c17d33..43877ce8bfee 100644 --- a/lms/djangoapps/ccx/tasks.py +++ b/lms/djangoapps/ccx/tasks.py @@ -7,7 +7,6 @@ from ccx_keys.locator import CCXLocator from django.dispatch import receiver -from edx_django_utils.monitoring import set_code_owner_attribute from opaque_keys import InvalidKeyError from opaque_keys.edx.locator import CourseLocator @@ -28,7 +27,6 @@ def course_published_handler(sender, course_key, **kwargs): # pylint: disable=u @CELERY_APP.task -@set_code_owner_attribute def send_ccx_course_published(course_key): """ Find all CCX derived from this course, and send course published event for them. diff --git a/lms/djangoapps/certificates/tasks.py b/lms/djangoapps/certificates/tasks.py index 93a7a05938b1..80c0fea7075d 100644 --- a/lms/djangoapps/certificates/tasks.py +++ b/lms/djangoapps/certificates/tasks.py @@ -9,7 +9,6 @@ from celery import shared_task from celery_utils.persist_on_failure import LoggedPersistOnFailureTask, LoggedTask from django.contrib.auth import get_user_model -from edx_django_utils.monitoring import set_code_owner_attribute from opaque_keys.edx.keys import CourseKey from lms.djangoapps.certificates.data import CertificateStatuses @@ -27,7 +26,6 @@ @shared_task( base=LoggedPersistOnFailureTask, bind=True, default_retry_delay=30, max_retries=2 ) -@set_code_owner_attribute def generate_certificate(self, **kwargs): # pylint: disable=unused-argument """ Generates a certificate for a single user. @@ -60,7 +58,6 @@ def generate_certificate(self, **kwargs): # pylint: disable=unused-argument @shared_task(base=LoggedTask, ignore_result=True) -@set_code_owner_attribute def handle_modify_cert_template(options: Dict[str, Any]) -> None: # noqa: UP006 """ Celery task to handle the modify_cert_template management command. diff --git a/lms/djangoapps/course_home_api/tasks.py b/lms/djangoapps/course_home_api/tasks.py index 39bc2bbb3c2a..06c883b094bd 100644 --- a/lms/djangoapps/course_home_api/tasks.py +++ b/lms/djangoapps/course_home_api/tasks.py @@ -5,7 +5,6 @@ from celery import shared_task from django.contrib.auth import get_user_model -from edx_django_utils.monitoring import set_code_owner_attribute from eventtracking import tracker from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey @@ -20,7 +19,6 @@ @shared_task -@set_code_owner_attribute def collect_progress_for_user_in_course(course_id: str, user_id: str) -> None: """ Celery task that retrieves a learner's progress in a given course. diff --git a/lms/djangoapps/discussion/rest_api/tasks.py b/lms/djangoapps/discussion/rest_api/tasks.py index 8fe8ee37dadb..943ec80466c6 100644 --- a/lms/djangoapps/discussion/rest_api/tasks.py +++ b/lms/djangoapps/discussion/rest_api/tasks.py @@ -5,7 +5,6 @@ from celery import shared_task from django.contrib.auth import get_user_model -from edx_django_utils.monitoring import set_code_owner_attribute from eventtracking import tracker from forum import api as forum_api from opaque_keys.edx.locator import CourseKey @@ -25,7 +24,6 @@ @shared_task -@set_code_owner_attribute def send_thread_created_notification(thread_id, course_key_str, user_id, notify_all_learners=False): """ Send notification when a new thread is created @@ -49,7 +47,6 @@ def send_thread_created_notification(thread_id, course_key_str, user_id, notify_ @shared_task -@set_code_owner_attribute def send_response_notifications(thread_id, course_key_str, user_id, comment_id, parent_id=None): """ Send notifications to users who are subscribed to the thread. @@ -68,7 +65,6 @@ def send_response_notifications(thread_id, course_key_str, user_id, comment_id, @shared_task -@set_code_owner_attribute def send_response_endorsed_notifications(thread_id, response_id, course_key_str, endorsed_by): """ Send notifications when a response is marked answered/ endorsed @@ -93,7 +89,6 @@ def send_response_endorsed_notifications(thread_id, response_id, course_key_str, @shared_task -@set_code_owner_attribute def delete_course_post_for_user(user_id, username, course_ids, event_data=None): """ Deletes all posts for user in a course. diff --git a/lms/djangoapps/discussion/tasks.py b/lms/djangoapps/discussion/tasks.py index bcb59ffdae02..777c937ed990 100644 --- a/lms/djangoapps/discussion/tasks.py +++ b/lms/djangoapps/discussion/tasks.py @@ -15,7 +15,6 @@ from edx_ace.channel import ChannelType 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 @@ -41,7 +40,6 @@ @shared_task(base=LoggedTask) -@set_code_owner_attribute def update_discussions_map(context): """ Updates the mapping between discussion_id to discussion block usage key @@ -78,7 +76,6 @@ class CommentNotification(BaseMessageType): @shared_task(base=LoggedTask) -@set_code_owner_attribute def send_ace_message(context): # pylint: disable=missing-function-docstring context['course_id'] = CourseKey.from_string(context['course_id']) @@ -119,7 +116,6 @@ def send_ace_message(context): # pylint: disable=missing-function-docstring @shared_task(base=LoggedTask) -@set_code_owner_attribute def send_ace_message_for_reported_content(context): # pylint: disable=missing-function-docstring context['course_id'] = CourseKey.from_string(context['course_id']) context['course_name'] = modulestore().get_course(context['course_id']).display_name diff --git a/lms/djangoapps/gating/tasks.py b/lms/djangoapps/gating/tasks.py index d58767637e81..04bc0cbf6364 100644 --- a/lms/djangoapps/gating/tasks.py +++ b/lms/djangoapps/gating/tasks.py @@ -7,7 +7,6 @@ from celery import shared_task from django.contrib.auth.models import User # pylint: disable=imported-auth-user -from edx_django_utils.monitoring import set_code_owner_attribute from opaque_keys.edx.keys import CourseKey, UsageKey from lms.djangoapps.course_blocks.api import get_course_blocks @@ -18,7 +17,6 @@ @shared_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 fa6cc23817b0..f00bed8ab1ba 100644 --- a/lms/djangoapps/grades/tasks.py +++ b/lms/djangoapps/grades/tasks.py @@ -10,7 +10,6 @@ from django.core.exceptions import ValidationError from django.db.utils import DatabaseError from edx_django_utils.monitoring import ( - set_code_owner_attribute, set_custom_attribute, set_custom_attributes_for_course_key, ) @@ -55,7 +54,6 @@ @shared_task(base=LoggedPersistOnFailureTask) -@set_code_owner_attribute def compute_all_grades_for_course(**kwargs): """ Compute grades for all students in the specified course. @@ -88,7 +86,6 @@ 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. @@ -113,7 +110,6 @@ def compute_grades_for_course_v2(self, **kwargs): @shared_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. @@ -141,7 +137,6 @@ def compute_grades_for_course(course_key, offset, batch_size, **kwargs): # pyli max_retries=2, default_retry_delay=RETRY_DELAY_SECONDS, ) -@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 @@ -182,7 +177,6 @@ def recalculate_course_and_subsection_grades_for_user(self, **kwargs): # pylint max_retries=2, default_retry_delay=RETRY_DELAY_SECONDS ) -@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/tasks.py b/lms/djangoapps/instructor/tasks.py index 8265be3b1187..63fb95bcaf86 100644 --- a/lms/djangoapps/instructor/tasks.py +++ b/lms/djangoapps/instructor/tasks.py @@ -5,7 +5,6 @@ from celery import shared_task from celery_utils.logged_task import LoggedTask from django.core.exceptions import ObjectDoesNotExist -from edx_django_utils.monitoring import set_code_owner_attribute from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import UsageKey from xblock.completable import XBlockCompletionMode @@ -21,7 +20,6 @@ @shared_task(base=LoggedTask, ignore_result=True) -@set_code_owner_attribute def update_exam_completion_task(user_identifier: str, content_id: str, completion: float) -> None: """ Marks all completable children of content_id as complete for the user. diff --git a/lms/djangoapps/instructor_task/tasks.py b/lms/djangoapps/instructor_task/tasks.py index 5baee74adbbc..7de7e4fddf9f 100644 --- a/lms/djangoapps/instructor_task/tasks.py +++ b/lms/djangoapps/instructor_task/tasks.py @@ -25,7 +25,6 @@ from celery import shared_task from django.utils.translation import gettext_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 @@ -59,7 +58,6 @@ @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def rescore_problem(entry_id, xblock_instance_args): """Rescores a problem in a course, for all students or one specific student. @@ -87,7 +85,6 @@ def rescore_problem(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def override_problem_score(entry_id, xblock_instance_args): """ Overrides a specific learner's score on a problem. @@ -101,7 +98,6 @@ def override_problem_score(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def reset_problem_attempts(entry_id, xblock_instance_args): """Resets problem attempts to zero for a particular problem for all students in a course. @@ -124,7 +120,6 @@ def reset_problem_attempts(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def delete_problem_state(entry_id, xblock_instance_args): """Deletes problem state entirely for all students on a particular problem in a course. @@ -147,7 +142,6 @@ def delete_problem_state(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def send_bulk_course_email(entry_id, _xblock_instance_args): """Sends emails to recipients enrolled in a course. @@ -172,7 +166,6 @@ def send_bulk_course_email(entry_id, _xblock_instance_args): name='lms.djangoapps.instructor_task.tasks.calculate_problem_responses_csv.v2', base=BaseInstructorTask, ) -@set_code_owner_attribute def calculate_problem_responses_csv(entry_id, xblock_instance_args): """ Compute student answers to a given problem and upload the CSV to @@ -185,7 +178,6 @@ def calculate_problem_responses_csv(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def calculate_grades_csv(entry_id, xblock_instance_args): """ Grade a course and push the results to an S3 bucket for download. @@ -202,7 +194,6 @@ def calculate_grades_csv(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def calculate_problem_grade_report(entry_id, xblock_instance_args): """ Generate a CSV for a course containing all students' problem @@ -220,7 +211,6 @@ def calculate_problem_grade_report(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def calculate_students_features_csv(entry_id, xblock_instance_args): """ Compute student profile information for a course and upload the @@ -233,7 +223,6 @@ def calculate_students_features_csv(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def course_survey_report_csv(entry_id, xblock_instance_args): """ Compute the survey report for a course and upload the @@ -246,7 +235,6 @@ def course_survey_report_csv(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def proctored_exam_results_csv(entry_id, xblock_instance_args): """ Compute proctored exam results report for a course and upload the @@ -258,7 +246,6 @@ def proctored_exam_results_csv(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def calculate_may_enroll_csv(entry_id, xblock_instance_args): """ Compute information about invited students who have not enrolled @@ -272,7 +259,6 @@ def calculate_may_enroll_csv(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def calculate_inactive_enrolled_students_info_csv(entry_id, xblock_instance_args): """ Compute information about invited students who have not enrolled @@ -286,7 +272,6 @@ def calculate_inactive_enrolled_students_info_csv(entry_id, xblock_instance_args @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def generate_certificates(entry_id, xblock_instance_args): """ Grade students and generate certificates. @@ -303,7 +288,6 @@ def generate_certificates(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def cohort_students(entry_id, xblock_instance_args): """ Cohort students in bulk, and upload the results. @@ -316,7 +300,6 @@ def cohort_students(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def generate_anonymous_ids_for_course(entry_id, xblock_instance_args): """ Generate a CSV of anonymize IDs for enrolled learner for course. @@ -329,7 +312,6 @@ def generate_anonymous_ids_for_course(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def export_ora2_data(entry_id, xblock_instance_args): """ Generate a CSV of ora2 responses and push it to S3. @@ -340,7 +322,6 @@ def export_ora2_data(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def export_ora2_submission_files(entry_id, xblock_instance_args): """ Download all submission files, generate csv downloads list, @@ -352,7 +333,6 @@ def export_ora2_submission_files(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def export_ora2_summary(entry_id, xblock_instance_args): """ Generate a CSV of ora2/student summaries and push it to S3. @@ -363,7 +343,6 @@ def export_ora2_summary(entry_id, xblock_instance_args): @shared_task(base=BaseInstructorTask) -@set_code_owner_attribute def student_enrollment_batch(entry_id, xblock_instance_args): """ Process student enrollment/unenrollment operations in batch asynchronously. diff --git a/lms/djangoapps/lti_provider/tasks.py b/lms/djangoapps/lti_provider/tasks.py index 365db52614b2..74537e40d965 100644 --- a/lms/djangoapps/lti_provider/tasks.py +++ b/lms/djangoapps/lti_provider/tasks.py @@ -6,7 +6,6 @@ import logging from django.contrib.auth.models import User # pylint: disable=imported-auth-user -from edx_django_utils.monitoring import set_code_owner_attribute from opaque_keys.edx.keys import CourseKey import lms.djangoapps.lti_provider.outcomes as outcomes @@ -19,7 +18,6 @@ @CELERY_APP.task(name='lms.djangoapps.lti_provider.tasks.send_composite_outcome') -@set_code_owner_attribute def send_composite_outcome(user_id, course_id, assignment_id, version): """ Calculate and transmit the score for a composite module (such as a @@ -69,7 +67,6 @@ def send_composite_outcome(user_id, course_id, assignment_id, version): @CELERY_APP.task -@set_code_owner_attribute def send_leaf_outcome(assignment_id, points_earned, points_possible): """ Calculate and transmit the score for a single problem. This method assumes diff --git a/lms/djangoapps/monitoring/README.rst b/lms/djangoapps/monitoring/README.rst index f61781c62ed4..702c50e9e4ea 100644 --- a/lms/djangoapps/monitoring/README.rst +++ b/lms/djangoapps/monitoring/README.rst @@ -1,13 +1,6 @@ Monitoring ========== -This directory contains utilities for adding a code_owner custom attribute for help with split-ownership of the LMS. - -For details on the decision to implement the code_owner custom attribute, see: -lms/djangoapps/monitoring/docs/decisions/0001-monitoring-by-code-owner.rst - -Originally, this directory contained the ``CodeOwnerMetricMiddleware``, but that has since been moved to -https://github.com/openedx/edx-django-utils/tree/master/edx_django_utils/monitoring/code_owner -and renamed ``CodeOwnerMonitoringMiddleware``. - -This directory continues to contain scripts that can help generate the appropriate ownership mappings for the LMS. +This directory previously contained utilities for the code_owner custom attribute +for split-ownership monitoring of the LMS. That functionality has been removed as +part of DEPR cleanup (openedx/edx-django-utils#469). diff --git a/lms/djangoapps/monitoring/docs/decisions/0001-monitoring-by-code-owner.rst b/lms/djangoapps/monitoring/docs/decisions/0001-monitoring-by-code-owner.rst deleted file mode 100644 index 6425e8e12a3f..000000000000 --- a/lms/djangoapps/monitoring/docs/decisions/0001-monitoring-by-code-owner.rst +++ /dev/null @@ -1,50 +0,0 @@ -Monitoring by Code Owner -************************ - -Status -====== - -Accepted - -Context -======= - -It is currently difficult for different teams to have team-based on-calls rotations, alerting and monitoring for various parts of the edx-platform (specifically LMS). - -Decision -======== - -We will implement a custom attribute "code_owner" that can be used in NewRelic (or other monitoring solutions that are made pluggable). - -The new custom attribute makes it simple to query NewRelic for all Transactions or TransactionErrors that are associated with requests with a specific owner. This enables a team to quickly identify data that they own, for use in NewRelic alerts or NewRelic dashboards. - -To minimize maintenance, the value of the "code_owner" attribute will be populated using the source-of-truth of ownership of various parts of edx-platform. - -See `Rejected Alternatives`_ for details of the decision **not** to split the NewRelic application into multiple NewRelic applications. - -Note: "owner" is a MySql reserved word, which NewRelic cautions against using, so we are using "code_owner". - -Consequences -============ - -This attribute should be quickly available for use with custom alerts and custom dashboards. - -In the future, this attribute could potentially be added to logging as well. - -Rejected Alternatives -===================== - -Splitting the NewRelic application ----------------------------------- - -The edx-platform (LMS) NewRelic application could have been split into multiple applications. This would have had the benefit of getting the out-of-the-box APM Dashboards for free. - -We decided against this alternative because: - -* To enable this solution, we would need to disable gunicorn instrumentation, and this instrumentation has proved to be valuable for understanding certain types of production issues. -* Splitting the app may make it more difficult to pinpoint the source of any problem that affects multiple applications. -* The application splitting depends on a slight "hack" from NewRelic, by resetting the application name for each path. - - * This "hack" goes against the grain of NewRelic's typical recommendations, so there could be unknown pitfalls. - * The mapping of request path to owner would require additional maintenance. - * Processing time is **not** accounted for in the NewRelic transaction time, because any processing required takes place before the NewRelic transaction gets started. diff --git a/lms/djangoapps/monitoring/scripts/clean_unmapped_view_modules.py b/lms/djangoapps/monitoring/scripts/clean_unmapped_view_modules.py deleted file mode 100644 index 77fb5fcf9c99..000000000000 --- a/lms/djangoapps/monitoring/scripts/clean_unmapped_view_modules.py +++ /dev/null @@ -1,74 +0,0 @@ -""" -Provided a CSV of data from our monitoring system, this script outputs a unique and clean -set of apps of unmapped view_func_modules. - -Context: This script was useful when first introducing ownership mapping and we had many -apps from 3rd-party dependencies that were missed. At this point, we'd probably only -expect 0-2 new unmapped apps, which could be cleaned manually very quickly without this -script. - -Sample usage:: - - python lms/djangoapps/monitoring/scripts/clean_unmapped_view_modules.py --unmapped-csv "unmapped-apps.csv" - -Or for more details:: - - python lms/djangoapps/monitoring/scripts/clean_unmapped_view_modules.py --help - - -""" -import csv - -import click - - -@click.command() -@click.option( - '--unmapped-csv', - help="File name of .csv file with unmapped edx-platform view modules.", - required=True -) -def main(unmapped_csv): - """ - Reads CSV of unmapped view_func_modules and outputs a clean list of apps to map. - - NewRelic Insights Query to create CSV of unmapped modules: - - \b - SELECT count(view_func_module) FROM Transaction - WHERE code_owner is null FACET view_func_module - SINCE 1 week ago - LIMIT 50 - - \b - * Increase or decrease SINCE clause as necessary based on when the mappings were last updated. - * Save results as CSV for use in script - - Sample CSV input:: - - \b - View Func Module,View Func Modules - enterprise.api.v1.views,1542 - edx_proctoring.views,116 - social_django.views,53 - - Script removes duplicates in addition to providing sorted list of plain app names. - - """ - with open(unmapped_csv) as file: - csv_data = file.read() - reader = csv.DictReader(csv_data.splitlines()) - - clean_apps_set = set() - for row in reader: - path = row.get('View Func Module') - path_parts = path.split('.') - clean_apps_set.add(path_parts[0]) - - print('# Move into generate_code_owner_mappings.py and complete mappings.') - for clean_app in sorted(clean_apps_set): - print(clean_app) - - -if __name__ == "__main__": - main() # pylint: disable=no-value-for-parameter diff --git a/lms/djangoapps/program_enrollments/tasks.py b/lms/djangoapps/program_enrollments/tasks.py index 300abc4d1054..46fc236e9b22 100644 --- a/lms/djangoapps/program_enrollments/tasks.py +++ b/lms/djangoapps/program_enrollments/tasks.py @@ -7,7 +7,6 @@ from celery import shared_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 @@ -15,7 +14,6 @@ @shared_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/support/tasks.py b/lms/djangoapps/support/tasks.py index b30e92a11a8b..083866958a3c 100644 --- a/lms/djangoapps/support/tasks.py +++ b/lms/djangoapps/support/tasks.py @@ -8,7 +8,6 @@ from django.contrib.sites.models import Site from edx_ace import ace from edx_ace.recipient import Recipient -from edx_django_utils.monitoring import set_code_owner_attribute from common.djangoapps.student.models.course_enrollment import CourseEnrollment from common.djangoapps.student.models.user import get_user_by_username_or_email @@ -45,7 +44,6 @@ def get_blocks(course): @shared_task -@set_code_owner_attribute def send_reset_course_completion_email(course, user): """ Sends email to a learner when whole course reset is complete. @@ -85,7 +83,6 @@ def send_reset_course_completion_email(course, user): @shared_task -@set_code_owner_attribute def reset_student_course(course_id, learner_email, reset_by_user_email): """ Resets a learner's course progress diff --git a/lms/djangoapps/verify_student/tasks.py b/lms/djangoapps/verify_student/tasks.py index ca0548cdd082..454f28960347 100644 --- a/lms/djangoapps/verify_student/tasks.py +++ b/lms/djangoapps/verify_student/tasks.py @@ -11,7 +11,6 @@ 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 @@ -73,7 +72,6 @@ def after_return(self, status, retval, task_id, args, kwargs, einfo): @shared_task -@set_code_owner_attribute def send_verification_status_email(context): """ Spins a task to send verification status email to the learner @@ -100,7 +98,6 @@ def send_verification_status_email(context): default_retry_delay=settings.SOFTWARE_SECURE_REQUEST_RETRY_DELAY, max_retries=settings.SOFTWARE_SECURE_RETRY_MAX_ATTEMPTS, ) -@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/lms/envs/common.py b/lms/envs/common.py index e8a185c1d49c..a6ea409164e7 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -1210,7 +1210,6 @@ # Various monitoring middleware 'edx_django_utils.monitoring.CachedCustomMonitoringMiddleware', - 'edx_django_utils.monitoring.CodeOwnerMonitoringMiddleware', 'edx_django_utils.monitoring.CookieMonitoringMiddleware', 'edx_django_utils.monitoring.DeploymentMonitoringMiddleware', 'edx_django_utils.monitoring.FrontendMonitoringMiddleware', diff --git a/openedx/core/djangoapps/bookmarks/tasks.py b/openedx/core/djangoapps/bookmarks/tasks.py index a35affb05180..91b405723dcc 100644 --- a/openedx/core/djangoapps/bookmarks/tasks.py +++ b/openedx/core/djangoapps/bookmarks/tasks.py @@ -7,7 +7,6 @@ from celery import shared_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,7 +144,6 @@ def update_block_cache_if_needed(block_cache, block_data): @shared_task(name='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 12a8cc7d9f33..77ecc3505cd7 100644 --- a/openedx/core/djangoapps/ccxcon/tasks.py +++ b/openedx/core/djangoapps/ccxcon/tasks.py @@ -5,7 +5,6 @@ from celery import shared_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 ( # pylint: disable=redefined-builtin ConnectionError, @@ -20,7 +19,6 @@ @shared_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/block_structure/tasks.py b/openedx/core/djangoapps/content/block_structure/tasks.py index 4490650fe06e..f5cd4e347fa4 100644 --- a/openedx/core/djangoapps/content/block_structure/tasks.py +++ b/openedx/core/djangoapps/content/block_structure/tasks.py @@ -7,7 +7,6 @@ from celery import shared_task from django.conf import settings -from edx_django_utils.monitoring import set_code_owner_attribute from edxval.api import ValInternalError from lxml.etree import XMLSyntaxError from opaque_keys.edx.keys import CourseKey @@ -36,7 +35,6 @@ def block_structure_task(**kwargs): @block_structure_task() -@set_code_owner_attribute def update_course_in_cache_v2(self, **kwargs): """ Updates the course blocks (mongo -> BlockStructure) for the specified course. @@ -47,7 +45,6 @@ def update_course_in_cache_v2(self, **kwargs): @block_structure_task() -@set_code_owner_attribute def update_course_in_cache(self, course_id): """ Updates the course blocks (mongo -> BlockStructure) for the specified course. @@ -63,7 +60,6 @@ def _update_course_in_cache(self, **kwargs): @block_structure_task() -@set_code_owner_attribute def get_course_in_cache_v2(self, **kwargs): """ Gets the course blocks for the specified course, updating the cache if needed. @@ -74,7 +70,6 @@ def get_course_in_cache_v2(self, **kwargs): @block_structure_task() -@set_code_owner_attribute def get_course_in_cache(self, course_id): """ Gets the course blocks for the specified course, updating the cache if needed. diff --git a/openedx/core/djangoapps/content/course_overviews/tasks.py b/openedx/core/djangoapps/content/course_overviews/tasks.py index 155a2011d40c..bf1fe0818816 100644 --- a/openedx/core/djangoapps/content/course_overviews/tasks.py +++ b/openedx/core/djangoapps/content/course_overviews/tasks.py @@ -5,7 +5,6 @@ from celery import shared_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 openedx.core.djangoapps.content.course_overviews.models import CourseOverview @@ -58,7 +57,6 @@ def enqueue_async_course_overview_update_tasks( # pylint: disable=missing-funct @shared_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/content/search/tasks.py b/openedx/core/djangoapps/content/search/tasks.py index a95bedb062db..2245cc85fa76 100644 --- a/openedx/core/djangoapps/content/search/tasks.py +++ b/openedx/core/djangoapps/content/search/tasks.py @@ -8,7 +8,6 @@ from celery import shared_task from celery_utils.logged_task import LoggedTask -from edx_django_utils.monitoring import set_code_owner_attribute from meilisearch.errors import MeilisearchError from opaque_keys.edx.keys import CourseKey, UsageKey from opaque_keys.edx.locator import ( @@ -24,7 +23,6 @@ @shared_task(base=LoggedTask, autoretry_for=(MeilisearchError, ConnectionError)) -@set_code_owner_attribute def upsert_xblock_index_doc(usage_key_str: str, recursive: bool) -> None: """ Celery task to update the content index document for an XBlock @@ -37,7 +35,6 @@ def upsert_xblock_index_doc(usage_key_str: str, recursive: bool) -> None: @shared_task(base=LoggedTask, autoretry_for=(MeilisearchError, ConnectionError)) -@set_code_owner_attribute def upsert_course_blocks_docs(course_key_str: str) -> None: """ Celery task to update the content index document for all XBlocks in a course. @@ -50,7 +47,6 @@ def upsert_course_blocks_docs(course_key_str: str) -> None: @shared_task(base=LoggedTask, autoretry_for=(MeilisearchError, ConnectionError)) -@set_code_owner_attribute def delete_xblock_index_doc(usage_key_str: str) -> None: """ Celery task to delete the content index document for an XBlock @@ -64,7 +60,6 @@ def delete_xblock_index_doc(usage_key_str: str) -> None: @shared_task(base=LoggedTask, autoretry_for=(MeilisearchError, ConnectionError)) -@set_code_owner_attribute def upsert_library_block_index_doc(usage_key_str: str) -> None: """ Celery task to update the content index document for a library block @@ -77,7 +72,6 @@ def upsert_library_block_index_doc(usage_key_str: str) -> None: @shared_task(base=LoggedTask, autoretry_for=(MeilisearchError, ConnectionError)) -@set_code_owner_attribute def delete_library_block_index_doc(usage_key_str: str) -> None: """ Celery task to delete the content index document for a library block @@ -90,7 +84,6 @@ def delete_library_block_index_doc(usage_key_str: str) -> None: @shared_task(base=LoggedTask, autoretry_for=(MeilisearchError, ConnectionError)) -@set_code_owner_attribute def update_content_library_index_docs(library_key_str: str, full_index: bool = False) -> None: """ Celery task to update the content index documents for all library blocks in a library @@ -104,7 +97,6 @@ def update_content_library_index_docs(library_key_str: str, full_index: bool = F @shared_task(base=LoggedTask, autoretry_for=(MeilisearchError, ConnectionError)) -@set_code_owner_attribute def update_library_collection_index_doc(collection_key_str: str) -> None: """ Celery task to update the content index document for a library collection @@ -118,7 +110,6 @@ def update_library_collection_index_doc(collection_key_str: str) -> None: @shared_task(base=LoggedTask, autoretry_for=(MeilisearchError, ConnectionError)) -@set_code_owner_attribute def update_library_components_collections(collection_key_str: str) -> None: """ Celery task to update the "collections" field for components in the given content library collection. @@ -132,7 +123,6 @@ def update_library_components_collections(collection_key_str: str) -> None: @shared_task(base=LoggedTask, autoretry_for=(MeilisearchError, ConnectionError)) -@set_code_owner_attribute def update_library_containers_collections(collection_key_str: str) -> None: """ Celery task to update the "collections" field for containers in the given content library collection. @@ -146,7 +136,6 @@ def update_library_containers_collections(collection_key_str: str) -> None: @shared_task(base=LoggedTask, autoretry_for=(MeilisearchError, ConnectionError)) -@set_code_owner_attribute def update_library_container_index_doc(container_key_str: str) -> None: """ Celery task to update the content index document for a library container @@ -160,7 +149,6 @@ def update_library_container_index_doc(container_key_str: str) -> None: @shared_task(base=LoggedTask, autoretry_for=(MeilisearchError, ConnectionError)) -@set_code_owner_attribute def delete_library_container_index_doc(container_key_str: str) -> None: """ Celery task to delete the content index document for a library block @@ -173,7 +161,6 @@ def delete_library_container_index_doc(container_key_str: str) -> None: @shared_task(base=LoggedTask, autoretry_for=(MeilisearchError, ConnectionError)) -@set_code_owner_attribute def delete_course_index_docs(course_key_str: str) -> None: """ Celery task to delete the content index documents for a Course @@ -192,7 +179,6 @@ def delete_course_index_docs(course_key_str: str) -> None: max_retries=3, retry_backoff=True, ) -@set_code_owner_attribute def rebuild_index_incremental() -> None: """ Celery task to incrementally populate the Studio Meilisearch index. diff --git a/openedx/core/djangoapps/content_libraries/tasks.py b/openedx/core/djangoapps/content_libraries/tasks.py index daea33a8ced6..ef84f77dec1f 100644 --- a/openedx/core/djangoapps/content_libraries/tasks.py +++ b/openedx/core/djangoapps/content_libraries/tasks.py @@ -35,8 +35,6 @@ from django.core.files.base import ContentFile from django.core.serializers.json import DjangoJSONEncoder from edx_django_utils.monitoring import ( - set_code_owner_attribute, - set_code_owner_attribute_from_module, set_custom_attribute, ) from opaque_keys import OpaqueKey @@ -92,7 +90,6 @@ @shared_task(base=LoggedTask) -@set_code_owner_attribute def send_change_events_for_modified_entities( learning_package_id: LearningPackage.ID, change_list: list[dict], # we want list[ChangeLogRecordData], but that's not JSON serializable, so use dicts @@ -228,7 +225,6 @@ def emit_collections_updated(library: ContentLibrary, entity_ids: list[Publishab @shared_task(base=LoggedTask) -@set_code_owner_attribute def check_container_content_changes( container_key_str: str, old_version_id: int | None, @@ -298,7 +294,6 @@ def check_container_content_changes( @shared_task(base=LoggedTask) -@set_code_owner_attribute def send_collections_changed_events( publishable_entity_ids: list[PublishableEntity.ID], learning_package_id: LearningPackage.ID, @@ -344,7 +339,6 @@ def send_collections_changed_events( @shared_task(base=LoggedTask) -@set_code_owner_attribute def send_events_after_publish(publish_log_id: int, library_key_str: str) -> None: """ Send events to trigger actions like updating the search index, after we've @@ -440,7 +434,6 @@ def generate_name(cls, arguments_dict) -> str: return f'Updating {key} from library' -# Note: The decorator @set_code_owner_attribute cannot be used here because the UserTaskMixin does stack # inspection and can't handle additional decorators. So, wet set the code_owner attribute in the tasks' bodies instead. @shared_task(base=LibrarySyncChildrenTask, bind=True) @@ -456,7 +449,6 @@ def sync_from_library( FIXME: this is related to legacy modulestore libraries and shouldn't be part of the openedx.core.djangoapps.content_libraries app, which is the app for v2 libraries. """ - set_code_owner_attribute_from_module(__name__) store = modulestore() dest_block = store.get_item(BlockUsageLocator.from_string(dest_block_id)) _sync_children( @@ -481,7 +473,6 @@ def duplicate_children( FIXME: this is related to legacy modulestore libraries and shouldn't be part of the openedx.core.djangoapps.content_libraries app, which is the app for v2 libraries. """ - set_code_owner_attribute_from_module(__name__) store = modulestore() # First, populate the destination block with children imported from the library. # It's important that _sync_children does this at the currently-set version of the dest library @@ -604,7 +595,6 @@ def generate_name(cls, arguments_dict) -> str: @shared_task(base=LibraryBackupTask, bind=True) -# Note: The decorator @set_code_owner_attribute cannot be used here because the UserTaskMixin # does stack inspection and can't handle additional decorators. def backup_library(self, user_id: int, library_key_str: str) -> None: """ @@ -616,7 +606,6 @@ def backup_library(self, user_id: int, library_key_str: str) -> None: - Failed: Task failed and the export did not complete. """ ensure_cms("backup_library may only be executed in a CMS context") - set_code_owner_attribute_from_module(__name__) library_key = LibraryLocatorV2.from_string(library_key_str) try: @@ -721,7 +710,6 @@ def restore_library(self, user_id, storage_path): Restore a learning package from a backup file. """ ensure_cms("restore_library may only be executed in a CMS context") - set_code_owner_attribute_from_module(__name__) TASK_LOGGER.info('Starting restore of learning package from %s', storage_path) diff --git a/openedx/core/djangoapps/content_staging/tasks.py b/openedx/core/djangoapps/content_staging/tasks.py index d676ad6acbcc..377ee5393919 100644 --- a/openedx/core/djangoapps/content_staging/tasks.py +++ b/openedx/core/djangoapps/content_staging/tasks.py @@ -7,7 +7,6 @@ from celery import shared_task from celery_utils.logged_task import LoggedTask -from edx_django_utils.monitoring import set_code_owner_attribute from .data import CLIPBOARD_PURPOSE from .models import StagedContent @@ -16,7 +15,6 @@ @shared_task(base=LoggedTask) -@set_code_owner_attribute def delete_expired_clipboards(staged_content_ids: list[StagedContent.ID]): """ A Celery task to delete StagedContent clipboard entries that are no longer diff --git a/openedx/core/djangoapps/content_tagging/tasks.py b/openedx/core/djangoapps/content_tagging/tasks.py index 8f67f737c2d3..4a9930907f98 100644 --- a/openedx/core/djangoapps/content_tagging/tasks.py +++ b/openedx/core/djangoapps/content_tagging/tasks.py @@ -9,7 +9,6 @@ from celery_utils.logged_task import LoggedTask from django.conf import settings from django.contrib.auth import get_user_model -from edx_django_utils.monitoring import set_code_owner_attribute from opaque_keys.edx.keys import CourseKey, UsageKey from opaque_keys.edx.locator import LibraryUsageLocatorV2 from openedx_tagging.models import Taxonomy @@ -59,7 +58,6 @@ def _delete_tags(content_object: ContentKey) -> None: @shared_task(base=LoggedTask) -@set_code_owner_attribute def update_course_tags(course_key_str: str) -> bool: """ Updates the automatically-managed tags for a course @@ -85,7 +83,6 @@ def update_course_tags(course_key_str: str) -> bool: @shared_task(base=LoggedTask) -@set_code_owner_attribute def delete_course_tags(course_key_str: str) -> bool: """ Delete the tags for a Course (when the course itself has been deleted). @@ -107,7 +104,6 @@ def delete_course_tags(course_key_str: str) -> bool: @shared_task(base=LoggedTask) -@set_code_owner_attribute def update_xblock_tags(usage_key_str: str) -> bool: """ Updates the automatically-managed tags for a XBlock @@ -138,7 +134,6 @@ def update_xblock_tags(usage_key_str: str) -> bool: @shared_task(base=LoggedTask) -@set_code_owner_attribute def delete_xblock_tags(usage_key_str: str) -> bool: """ Delete the tags for a XBlock (when the XBlock itself is deleted). @@ -160,7 +155,6 @@ def delete_xblock_tags(usage_key_str: str) -> bool: @shared_task(base=LoggedTask) -@set_code_owner_attribute def update_library_block_tags(usage_key_str: str, language_code: str) -> bool: """ Updates the automatically-managed tags for a content library block @@ -183,7 +177,6 @@ def update_library_block_tags(usage_key_str: str, language_code: str) -> bool: @shared_task(base=LoggedTask) -@set_code_owner_attribute def delete_library_block_tags(usage_key_str: str) -> bool: """ Delete the tags for a Library Block (when the Library Block itself is deleted). diff --git a/openedx/core/djangoapps/course_apps/tasks.py b/openedx/core/djangoapps/course_apps/tasks.py index 1448c6e3dfff..64e287510a02 100644 --- a/openedx/core/djangoapps/course_apps/tasks.py +++ b/openedx/core/djangoapps/course_apps/tasks.py @@ -4,7 +4,6 @@ from celery import shared_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 opaque_keys.edx.locator import LibraryLocator @@ -16,7 +15,6 @@ @shared_task(name='openedx.core.djangoapps.course_apps.tasks.cache_all_course_apps_status') -@set_code_owner_attribute def cache_all_course_apps_status(): """ Create CourseAppStatus entries for all course apps, across all courses to speed up queries. @@ -31,7 +29,6 @@ def cache_all_course_apps_status(): @shared_task(name='openedx.core.djangoapps.course_apps.tasks.update_course_apps_status') -@set_code_owner_attribute def update_course_apps_status(course_key_str: str): """ Create CourseAppStatus entries for apps available for the specified course. diff --git a/openedx/core/djangoapps/credentials/tasks/v1/tasks.py b/openedx/core/djangoapps/credentials/tasks/v1/tasks.py index 953d138cbfc9..62eb4a35a661 100644 --- a/openedx/core/djangoapps/credentials/tasks/v1/tasks.py +++ b/openedx/core/djangoapps/credentials/tasks/v1/tasks.py @@ -11,7 +11,6 @@ from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.sites.models import Site -from edx_django_utils.monitoring import set_code_owner_attribute from MySQLdb import OperationalError from opaque_keys.edx.keys import CourseKey @@ -52,7 +51,6 @@ retry_backoff_max=600, retry_jitter=True, ) -@set_code_owner_attribute def send_grade_to_credentials( self, username, @@ -100,7 +98,6 @@ def send_grade_to_credentials( @shared_task(base=LoggedTask, ignore_result=True) -@set_code_owner_attribute def handle_notify_credentials(options, course_keys): """ Celery task to handle the notify_credentials management command. Finds the relevant cert and grade records, then @@ -425,7 +422,6 @@ def is_course_run_in_a_program(course_run_key): @shared_task(base=LoggedTask, ignore_result=True) -@set_code_owner_attribute def backfill_date_for_all_course_runs(): """ This task enqueues an `update_certificate_available_date_on_course_update` subtask for each course overview in the diff --git a/openedx/core/djangoapps/credit/tasks.py b/openedx/core/djangoapps/credit/tasks.py index a8227e504352..1d012a27571a 100644 --- a/openedx/core/djangoapps/credit/tasks.py +++ b/openedx/core/djangoapps/credit/tasks.py @@ -6,7 +6,6 @@ from celery import shared_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,7 +19,6 @@ @shared_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/discussions/tasks.py b/openedx/core/djangoapps/discussions/tasks.py index 4599f33454d4..747a088fa098 100644 --- a/openedx/core/djangoapps/discussions/tasks.py +++ b/openedx/core/djangoapps/discussions/tasks.py @@ -4,7 +4,6 @@ import logging from celery import shared_task -from edx_django_utils.monitoring import set_code_owner_attribute from opaque_keys.edx.keys import CourseKey from openedx_events.learning.data import CourseDiscussionConfigurationData, DiscussionTopicContext from openedx_events.learning.signals import COURSE_DISCUSSIONS_CHANGED @@ -20,7 +19,6 @@ @shared_task -@set_code_owner_attribute def update_discussions_settings_from_course_task(course_key_str: str, discussable_units=None): """ Celery task that creates or updates discussions settings for a course. diff --git a/openedx/core/djangoapps/heartbeat/tasks.py b/openedx/core/djangoapps/heartbeat/tasks.py index 0c18560755ef..16d6293fc36c 100644 --- a/openedx/core/djangoapps/heartbeat/tasks.py +++ b/openedx/core/djangoapps/heartbeat/tasks.py @@ -4,10 +4,8 @@ from celery import shared_task -from edx_django_utils.monitoring import set_code_owner_attribute @shared_task -@set_code_owner_attribute def sample_task(): return True diff --git a/openedx/core/djangoapps/notifications/email/tasks.py b/openedx/core/djangoapps/notifications/email/tasks.py index ded2edb5178f..3d3703317f2d 100644 --- a/openedx/core/djangoapps/notifications/email/tasks.py +++ b/openedx/core/djangoapps/notifications/email/tasks.py @@ -14,7 +14,6 @@ from django.utils.translation import override as translation_override from edx_ace import ace from edx_ace.recipient import Recipient -from edx_django_utils.monitoring import set_code_owner_attribute from openedx.core.djangoapps.notifications.email_notifications import EmailCadence from openedx.core.djangoapps.notifications.models import ( @@ -338,7 +337,6 @@ def _enqueue_bulk_digest_tasks(uids, ctype, dtime): @shared_task(bind=True, ignore_result=True, max_retries=3, default_retry_delay=300) -@set_code_owner_attribute def send_user_digest_email_task(self, user_id, cadence_type): """ Delayed Celery task to send a digest email to a single user. @@ -719,7 +717,6 @@ def add_to_existing_buffer(notification: Notification) -> None: @shared_task(bind=True, max_retries=3, default_retry_delay=60) -@set_code_owner_attribute def send_buffered_digest( self, user_id: int, diff --git a/openedx/core/djangoapps/notifications/tasks.py b/openedx/core/djangoapps/notifications/tasks.py index 4dc8c76b1f6a..7cca299a28a5 100644 --- a/openedx/core/djangoapps/notifications/tasks.py +++ b/openedx/core/djangoapps/notifications/tasks.py @@ -9,7 +9,6 @@ from celery.utils.log import get_task_logger from django.conf import settings from django.core.exceptions import ValidationError -from edx_django_utils.monitoring import set_code_owner_attribute from opaque_keys.edx.keys import CourseKey from openedx.core.djangoapps.notifications.audience_filters import NotificationFilter @@ -46,7 +45,6 @@ @shared_task(ignore_result=True) -@set_code_owner_attribute def delete_notifications(kwargs): """ Delete notifications @@ -72,7 +70,6 @@ def delete_notifications(kwargs): @shared_task(ignore_result=True) -@set_code_owner_attribute def delete_expired_notifications(): """ This task deletes all expired notifications @@ -100,7 +97,6 @@ def delete_expired_notifications(): # pylint: disable=too-many-statements @shared_task -@set_code_owner_attribute def send_notifications(user_ids, course_key: str, app_name, notification_type, context, content_url): """ Send notifications to the users. diff --git a/openedx/core/djangoapps/programs/tasks.py b/openedx/core/djangoapps/programs/tasks.py index 43dce6f392a3..4c25b0a6c455 100644 --- a/openedx/core/djangoapps/programs/tasks.py +++ b/openedx/core/djangoapps/programs/tasks.py @@ -13,7 +13,6 @@ from django.contrib.auth import get_user_model from django.contrib.sites.models import Site from django.core.exceptions import ObjectDoesNotExist -from edx_django_utils.monitoring import set_code_owner_attribute from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey from requests.exceptions import HTTPError @@ -271,7 +270,6 @@ def post_course_certificate_configuration(client, cert_config, certificate_avail retry_backoff_max=600, retry_jitter=True, ) -@set_code_owner_attribute def award_program_certificates(self, username): # pylint: disable=too-many-statements """ This task is designed to be called whenever a student's completion status changes with respect to one or more @@ -421,7 +419,6 @@ def award_program_certificates(self, username): # pylint: disable=too-many-stat retry_backoff_max=600, retry_jitter=True, ) -@set_code_owner_attribute def update_credentials_course_certificate_configuration_available_date( self, course_key, certificate_available_date=None ): @@ -474,7 +471,6 @@ def update_credentials_course_certificate_configuration_available_date( retry_backoff_max=600, retry_jitter=True, ) -@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, or when a course-run's @@ -592,7 +588,6 @@ def award_course_certificate(self, username, course_run_key): retry_backoff_max=600, retry_jitter=True, ) -@set_code_owner_attribute def revoke_program_certificates(self, username, course_key): # pylint: disable=too-many-statements """ This task is designed to be called whenever a student's course certificate is revoked. @@ -725,7 +720,6 @@ def revoke_program_certificates(self, username, course_key): # pylint: disable= retry_backoff_max=600, retry_jitter=True, ) -@set_code_owner_attribute def update_certificate_available_date_on_course_update(self, course_key): """ This task is designed to be enqueued whenever a course run's Certificate Display Behavior (CDB) or Certificate diff --git a/openedx/core/djangoapps/schedules/tasks.py b/openedx/core/djangoapps/schedules/tasks.py index a7d92055fa37..8e67c210e03a 100644 --- a/openedx/core/djangoapps/schedules/tasks.py +++ b/openedx/core/djangoapps/schedules/tasks.py @@ -16,8 +16,6 @@ from edx_ace.message import Message from edx_ace.utils.date import deserialize, serialize from edx_django_utils.monitoring import ( - set_code_owner_attribute, - set_code_owner_attribute_from_module, set_custom_attribute, ) from eventtracking import tracker @@ -46,7 +44,6 @@ @shared_task(base=LoggedPersistOnFailureTask, bind=True, default_retry_delay=30) -@set_code_owner_attribute def update_course_schedules(self, **kwargs): # pylint: disable=missing-function-docstring course_key = CourseKey.from_string(kwargs['course_id']) new_start_date = deserialize(kwargs['new_start_date_str']) @@ -105,7 +102,6 @@ class BinnedScheduleMessageBaseTask(ScheduleMessageBaseTask): @classmethod def enqueue(cls, site, current_date, day_offset, override_recipient_email=None, override_middlewares=None): # pylint: disable=missing-function-docstring - set_code_owner_attribute_from_module(__name__) current_date = resolvers._get_datetime_beginning_of_day(current_date) # pylint: disable=protected-access if not cls.is_enqueue_enabled(site): @@ -132,7 +128,6 @@ def enqueue(cls, site, current_date, day_offset, override_recipient_email=None, def run( # pylint: disable=arguments-differ self, site_id, target_day_str, day_offset, bin_num, override_recipient_email=None, override_middlewares=None, ): - set_code_owner_attribute_from_module(__name__) site = Site.objects.select_related('configuration').get(id=site_id) middlewares = [self.class_from_classpath(cls) for cls in override_middlewares] if override_middlewares else None with emulate_http_request(site=site, middleware_classes=middlewares) as request: @@ -157,7 +152,6 @@ def class_from_classpath(self, class_path): @shared_task(base=LoggedTask, ignore_result=True) -@set_code_owner_attribute def _recurring_nudge_schedule_send(site_id, msg_str): _schedule_send( msg_str, @@ -168,7 +162,6 @@ def _recurring_nudge_schedule_send(site_id, msg_str): @shared_task(base=LoggedTask, ignore_result=True) -@set_code_owner_attribute def _upgrade_reminder_schedule_send(site_id, msg_str): _schedule_send( msg_str, @@ -179,7 +172,6 @@ def _upgrade_reminder_schedule_send(site_id, msg_str): @shared_task(base=LoggedTask, ignore_result=True) -@set_code_owner_attribute def _course_update_schedule_send(site_id, msg_str): _schedule_send( msg_str, @@ -240,7 +232,6 @@ class ScheduleCourseNextSectionUpdate(ScheduleMessageBaseTask): # pylint: disab @classmethod def enqueue(cls, site, current_date, day_offset, override_recipient_email=None): # pylint: disable=missing-function-docstring - set_code_owner_attribute_from_module(__name__) target_datetime = (current_date - datetime.timedelta(days=day_offset)) if not cls.is_enqueue_enabled(site): @@ -262,7 +253,6 @@ def enqueue(cls, site, current_date, day_offset, override_recipient_email=None): ) def run(self, site_id, target_day_str, course_key, override_recipient_email=None): # pylint: disable=arguments-differ - set_code_owner_attribute_from_module(__name__) site = Site.objects.select_related('configuration').get(id=site_id) with emulate_http_request(site=site): _annotate_for_monitoring(message_types.CourseUpdate(), site, 0, target_day_str, -1) diff --git a/openedx/core/djangoapps/service_status/tasks.py b/openedx/core/djangoapps/service_status/tasks.py index 61b35d7a4cc5..6ba3cd33482c 100644 --- a/openedx/core/djangoapps/service_status/tasks.py +++ b/openedx/core/djangoapps/service_status/tasks.py @@ -6,11 +6,9 @@ import time from celery import current_app as celery -from edx_django_utils.monitoring import set_code_owner_attribute @celery.task -@set_code_owner_attribute def delayed_ping(value, delay): """A simple tasks that replies to a message after a especified amount of seconds. diff --git a/openedx/core/djangoapps/user_authn/tasks.py b/openedx/core/djangoapps/user_authn/tasks.py index b54e761dd25f..2d368c1d1c78 100644 --- a/openedx/core/djangoapps/user_authn/tasks.py +++ b/openedx/core/djangoapps/user_authn/tasks.py @@ -12,7 +12,6 @@ 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 common.djangoapps.track import segment from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers @@ -23,7 +22,6 @@ @shared_task -@set_code_owner_attribute def check_pwned_password_and_send_track_event( user_id, password, internal_user=False, @@ -50,7 +48,6 @@ def check_pwned_password_and_send_track_event( @shared_task(bind=True, default_retry_delay=30, max_retries=2) -@set_code_owner_attribute def send_activation_email(self, msg_string, from_address=None, site_id=None): """ Sending an activation email to the user. diff --git a/openedx/features/enterprise_support/tasks.py b/openedx/features/enterprise_support/tasks.py index f41da3031076..248461a627de 100644 --- a/openedx/features/enterprise_support/tasks.py +++ b/openedx/features/enterprise_support/tasks.py @@ -6,7 +6,6 @@ import logging from celery import shared_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 @@ -15,7 +14,6 @@ @shared_task(name='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/openedx/features/survey_report/tasks.py b/openedx/features/survey_report/tasks.py index ff7fe2ac64f2..8e775db8571e 100644 --- a/openedx/features/survey_report/tasks.py +++ b/openedx/features/survey_report/tasks.py @@ -6,7 +6,6 @@ import logging from celery import shared_task -from edx_django_utils.monitoring import set_code_owner_attribute from .api import generate_report @@ -14,7 +13,6 @@ @shared_task(name='openedx.features.survey_report.tasks.generate_survey_report') -@set_code_owner_attribute def generate_survey_report(): """ Tasks to generate a new survey report with non-sensitive data. diff --git a/requirements/edx/semgrep.in b/requirements/edx/semgrep.in deleted file mode 100644 index 0fc07d64532b..000000000000 --- a/requirements/edx/semgrep.in +++ /dev/null @@ -1,13 +0,0 @@ -# Requirements to run Semgrep code quality checks -# -# DON'T JUST ADD NEW DEPENDENCIES!!! -# -# If you open a pull request that adds a new dependency, you should: -# * verify that the dependency has a license compatible with AGPLv3 -# * confirm that it has no system requirements beyond what we already install -# * run "make upgrade" to update the detailed requirements files -# - --c ../constraints.txt - -semgrep # Semgrep performs structural code searches diff --git a/requirements/edx/semgrep.txt b/requirements/edx/semgrep.txt deleted file mode 100644 index 51f2d11db551..000000000000 --- a/requirements/edx/semgrep.txt +++ /dev/null @@ -1,213 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.12 -# by the following command: -# -# make upgrade -# -annotated-types==0.8.0 - # via pydantic -anyio==4.14.2 - # via - # httpx - # mcp - # sse-starlette - # starlette -attrs==26.1.0 - # via - # glom - # jsonschema - # referencing - # semgrep -boltons==21.0.0 - # via - # face - # glom - # semgrep -bracex==3.0.1 - # via wcmatch -certifi==2026.7.22 - # via - # httpcore - # httpx - # requests -cffi==2.1.0 - # via cryptography -charset-normalizer==3.4.9 - # via requests -click==8.4.2 - # via - # click-option-group - # semgrep - # uvicorn -click-option-group==0.5.9 - # via semgrep -colorama==0.4.6 - # via semgrep -cryptography==49.0.0 - # via pyjwt -exceptiongroup==1.2.2 - # via semgrep -face==26.0.1 - # via glom -glom==25.12.0 - # via semgrep -googleapis-common-protos==1.75.0 - # via opentelemetry-exporter-otlp-proto-http -h11==0.16.0 - # via - # httpcore - # uvicorn -httpcore==1.0.9 - # via httpx -httpx==0.28.1 - # via mcp -httpx-sse==0.4.3 - # via mcp -idna==3.18 - # via - # anyio - # httpx - # requests -importlib-metadata==8.7.1 - # via opentelemetry-api -jsonschema==4.25.1 - # via - # mcp - # semgrep -jsonschema-specifications==2025.9.1 - # via jsonschema -markdown-it-py==4.2.0 - # via rich -mcp==1.23.3 - # via semgrep -mdurl==0.1.2 - # via markdown-it-py -opentelemetry-api==1.37.0 - # via - # opentelemetry-exporter-otlp-proto-http - # opentelemetry-instrumentation - # opentelemetry-instrumentation-requests - # opentelemetry-instrumentation-threading - # opentelemetry-sdk - # opentelemetry-semantic-conventions - # semgrep -opentelemetry-exporter-otlp-proto-common==1.37.0 - # via opentelemetry-exporter-otlp-proto-http -opentelemetry-exporter-otlp-proto-http==1.37.0 - # via semgrep -opentelemetry-instrumentation==0.58b0 - # via - # opentelemetry-instrumentation-requests - # opentelemetry-instrumentation-threading -opentelemetry-instrumentation-requests==0.58b0 - # via semgrep -opentelemetry-instrumentation-threading==0.58b0 - # via semgrep -opentelemetry-proto==1.37.0 - # via - # opentelemetry-exporter-otlp-proto-common - # opentelemetry-exporter-otlp-proto-http -opentelemetry-sdk==1.37.0 - # via - # opentelemetry-exporter-otlp-proto-http - # semgrep -opentelemetry-semantic-conventions==0.58b0 - # via - # opentelemetry-instrumentation - # opentelemetry-instrumentation-requests - # opentelemetry-sdk -opentelemetry-util-http==0.58b0 - # via opentelemetry-instrumentation-requests -packaging==26.2 - # via - # opentelemetry-instrumentation - # semgrep -peewee==3.19.0 - # via semgrep -protobuf==6.33.6 - # via - # googleapis-common-protos - # opentelemetry-proto -pycparser==3.0 - # via cffi -pydantic==2.13.4 - # via - # mcp - # pydantic-settings -pydantic-core==2.46.4 - # via pydantic -pydantic-settings==2.14.2 - # via mcp -pygments==2.20.0 - # via rich -pyjwt[crypto]==2.13.0 - # via - # mcp - # semgrep -python-dotenv==1.2.2 - # via pydantic-settings -python-multipart==0.0.32 - # via mcp -referencing==0.37.0 - # via - # jsonschema - # jsonschema-specifications -requests==2.34.2 - # via - # opentelemetry-exporter-otlp-proto-http - # semgrep -rich==15.0.0 - # via semgrep -rpds-py==2026.6.3 - # via - # jsonschema - # referencing -ruamel-yaml==0.19.1 - # via semgrep -ruamel-yaml-clib==0.2.15 - # via semgrep -semantic-version==2.10.0 - # via semgrep -semgrep==1.171.0 - # via -r requirements/edx/semgrep.in -sse-starlette==3.4.6 - # via mcp -starlette==1.3.1 - # via - # mcp - # sse-starlette -tomli==2.4.1 - # via semgrep -typing-extensions==4.16.0 - # via - # anyio - # mcp - # opentelemetry-api - # opentelemetry-exporter-otlp-proto-http - # opentelemetry-sdk - # opentelemetry-semantic-conventions - # pydantic - # pydantic-core - # referencing - # semgrep - # starlette - # typing-inspection -typing-inspection==0.4.2 - # via - # mcp - # pydantic - # pydantic-settings -urllib3==2.7.0 - # via - # requests - # semgrep -uvicorn==0.51.0 - # via mcp -wcmatch==8.5.2 - # via semgrep -wrapt==1.17.3 - # via - # opentelemetry-instrumentation - # opentelemetry-instrumentation-threading -zipp==4.1.0 - # via importlib-metadata diff --git a/test_root/semgrep/README.rst b/test_root/semgrep/README.rst deleted file mode 100644 index 92fa16f1bf05..000000000000 --- a/test_root/semgrep/README.rst +++ /dev/null @@ -1,21 +0,0 @@ -Semgrep linters -############### - -Linting rules for use with `semgrep`_ during CI checks on PRs. - -Status -****** - -This is an experimental approach to developing new linting rules. Semgrep provides by-example structural matching that can be easier to write and maintain than procedural code inspecting ASTs. If the approach works out, we can expand our use of Semgrep; if it becomes a problem for some reason, we can switch to adding pylint rules in edx-lint. - -Ignoring failures -***************** - -If you need to tell semgrep to ignore a block of code, put a ``# nosemgrep`` comment on or before the first matched line. - -Documentation for writing new rules: - -- https://semgrep.dev/docs/writing-rules/rule-syntax/ -- https://semgrep.dev/docs/writing-rules/pattern-syntax/ - -.. _semgrep: https://github.com/returntocorp/semgrep diff --git a/test_root/semgrep/celery-code-owner.yml b/test_root/semgrep/celery-code-owner.yml deleted file mode 100644 index a1693752d2ff..000000000000 --- a/test_root/semgrep/celery-code-owner.yml +++ /dev/null @@ -1,104 +0,0 @@ -rules: - - id: celery-missing-code-owner-function - # We can't link directly to the howto doc in question because - # semgrep has a bug around long lines: - # https://github.com/returntocorp/semgrep/issues/8608 - # - # Here's the intended URL, for reference: - # https://docs.openedx.org/projects/edx-django-utils/en/latest/monitoring/how_tos/add_code_owner_custom_attribute_to_an_ida.html#handling-celery-tasks - message: | - Celery tasks need to be decorated with `@set_code_owner_attribute` - (from the `edx_django_utils.monitoring` module) in order for us - to correctly track code-owners for errors and in other monitoring. - - For more information, see the Celery section of "Add Code_Owner - Custom Attributes to an IDA" in the Monitoring How-Tos of - . - languages: - - python - patterns: - # Find functions with decorators containing the substring "task" - # in their name. This might end up with false positives, but - # there are a lot of variations on how we decorate Celery tasks. - - # This pattern should match all decorators, whether or not - # they're called as a function (both `@foo(...)` and `@foo`) - # and whether or not there are other decorators above or below. - - pattern-either: - - pattern: | - @$TASK - def $F(...): - ... - - pattern: | - @$TASK(...) - def $F(...): - ... - - # Restrict the decorators of interest to just ones with "task" - # in the name. - - metavariable-pattern: - metavariable: $TASK - patterns: - - pattern-regex: >- - [^\(]*task(\(|$) - - # Filter out all of the properly annotated functions, leaving - # just the ones of interest. - - pattern-not: | - @set_code_owner_attribute - def $F(...): - ... - # This is an alternative approach that we have needed in rare cases. - - pattern-not: | - def $F(...): - ... - set_code_owner_attribute_from_module(...) - - severity: WARNING - - # This is like celery-missing-code-owner-function but for the `run` - # method of Task classes. - - id: celery-missing-code-owner-class - message: | - Celery task classes need to decorate their `run` method with - `@set_code_owner_attribute` (imported from `edx_django_utils.monitoring`) - in order for us to correctly track code-owners for errors and in other - monitoring. Alternatively, the `run` method can call - `set_code_owner_attribute_from_module`. - - For more information, see the Celery section of "Add Code_Owner - Custom Attributes to an IDA" in the Monitoring How-Tos of - . - languages: - - python - patterns: - - pattern: | - class $C(..., $SUPER, ...): - def run(...): - ... - - metavariable-pattern: - metavariable: $SUPER - patterns: - - pattern-regex: "Task$" - - - pattern-not: | - class $C(..., $SUPER, ...): - - @set_code_owner_attribute - def run(...): - ... - - - pattern-not: | - class $C(..., $SUPER, ...): - - @set_code_owner_attribute - def run(...): - ... - - pattern-not: | - class $C(..., $SUPER, ...): - - def run(...): - ... - set_code_owner_attribute_from_module(...) - - severity: WARNING diff --git a/xmodule/modulestore/django.py b/xmodule/modulestore/django.py index 82638265976f..0b3790008843 100644 --- a/xmodule/modulestore/django.py +++ b/xmodule/modulestore/django.py @@ -165,7 +165,6 @@ class SignalHandler: from django.dispatch import receiver from celery import shared_task - from edx_django_utils.monitoring import set_code_owner_attribute from xmodule.modulestore.django import modulestore, SignalHandler @receiver(SignalHandler.course_published) @@ -173,7 +172,6 @@ def listen_for_course_publish(sender, course_key, **kwargs): do_my_expensive_update.delay(course_key) @shared_task() - @set_code_owner_attribute def do_my_expensive_update(course_key): # ...