Browse Source

ref: Move recording first transaction to save_event from post_process (#25930)

One more step towards removing transactions post processing. This change
moves the recording of the first transaction for a project from the
post processing phase earlier to the save event task.

This change makes recording of the first transaction consistent with the way the
first non transaction event is recorded, which is also done in save_event. The
recording of the first transaction event is now handled in the same part of the
ingestion pipeline as the recording of the first error event.
Lyn Nagara 3 years ago
parent
commit
2296d2b639

+ 7 - 2
src/sentry/event_manager.py

@@ -65,7 +65,7 @@ from sentry.reprocessing2 import (
     is_reprocessed_event,
     save_unprocessed_event,
 )
-from sentry.signals import first_event_received, issue_unresolved
+from sentry.signals import first_event_received, first_transaction_received, issue_unresolved
 from sentry.stacktraces.processing import normalize_stacktraces_for_grouping
 from sentry.tasks.integrations import kick_off_status_syncs
 from sentry.utils import json, metrics
@@ -306,6 +306,12 @@ class EventManager:
             self._data["project"] = int(project_id)
             job = {"data": self._data, "start_time": start_time}
             jobs = save_transaction_events([job], projects)
+
+            if not project.flags.has_transactions:
+                first_transaction_received.send_robust(
+                    project=project, event=jobs[0]["event"], sender=Project
+                )
+
             return jobs[0]["event"]
 
         with metrics.timer("event_manager.save.organization.get_from_cache"):
@@ -473,7 +479,6 @@ class EventManager:
                         "environment_id": job["environment"].id,
                     },
                 )
-
         if not raw:
             if not project.first_event:
                 project.update(first_event=job["event"].datetime)

+ 11 - 18
src/sentry/receivers/onboarding.py

@@ -1,7 +1,7 @@
 import logging
 
 from django.db import IntegrityError, transaction
-from django.db.models import Q
+from django.db.models import F, Q
 from django.utils import timezone
 
 from sentry import analytics
@@ -11,6 +11,7 @@ from sentry.models import (
     Organization,
     OrganizationOnboardingTask,
     OrganizationOption,
+    Project,
 )
 from sentry.plugins.bases import IssueTrackingPlugin, IssueTrackingPlugin2
 from sentry.plugins.bases.notify import NotificationPlugin
@@ -19,6 +20,7 @@ from sentry.signals import (
     event_processed,
     first_event_pending,
     first_event_received,
+    first_transaction_received,
     issue_tracker_used,
     member_invited,
     member_joined,
@@ -110,18 +112,10 @@ def record_raven_installed(project, user, **kwargs):
 
 @first_event_received.connect(weak=False)
 def record_first_event(project, event, **kwargs):
-    if event.get_event_type() == "transaction":
-        record_first_transaction(project, event)
-    else:
-        record_first_error(project, event)
-
-
-def record_first_error(project, event):
     """
     Requires up to 2 database calls, but should only run with the first event in
     any project, so performance should not be a huge bottleneck.
     """
-
     # If complete, pass (creation fails due to organization, task unique constraint)
     # If pending, update.
     # If does not exist, create.
@@ -186,7 +180,10 @@ def record_first_error(project, event):
             )
 
 
-def record_first_transaction(project, event):
+@first_transaction_received.connect(weak=False)
+def record_first_transaction(project, event, **kwargs):
+    project.update(flags=F("flags").bitor(Project.flags.has_transactions))
+
     OrganizationOnboardingTask.objects.record(
         organization_id=project.organization_id,
         task=OnboardingTask.FIRST_TRANSACTION,
@@ -195,20 +192,16 @@ def record_first_transaction(project, event):
     )
 
     try:
-        user = Organization.objects.get(id=project.organization_id).get_default_owner()
+        default_user_id = project.organization.get_default_owner().id
     except IndexError:
-        logging.getLogger("sentry").warn(
-            "Cannot record first transaction for organization (%s) due to missing owners",
-            project.organization_id,
-        )
-        return
+        default_user_id = None
 
     analytics.record(
         "first_transaction.sent",
-        user_id=user.id,
+        default_user_id=default_user_id,
         organization_id=project.organization_id,
         project_id=project.id,
-        platform=event.platform,
+        platform=project.platform,
     )
 
 

+ 0 - 24
src/sentry/receivers/transactions.py

@@ -1,24 +0,0 @@
-from django.db.models import F
-
-from sentry import analytics
-from sentry.models import Project
-from sentry.signals import transaction_processed
-
-
-@transaction_processed.connect(weak=False)
-def record_first_transaction(project, event, **kwargs):
-    if not project.flags.has_transactions:
-        project.update(flags=F("flags").bitor(Project.flags.has_transactions))
-
-        try:
-            default_user_id = project.organization.get_default_owner().id
-        except IndexError:
-            default_user_id = None
-
-        analytics.record(
-            "first_transaction.sent",
-            default_user_id=default_user_id,
-            project_id=project.id,
-            organization_id=project.organization_id,
-            platform=project.platform,
-        )

+ 2 - 0
src/sentry/signals.py

@@ -64,7 +64,9 @@ event_accepted = BetterSignal(providing_args=["ip", "data", "project"])
 # Organization Onboarding Signals
 project_created = BetterSignal(providing_args=["project", "user", "default_rules"])
 first_event_pending = BetterSignal(providing_args=["project", "user"])
+
 first_event_received = BetterSignal(providing_args=["project", "event"])
+first_transaction_received = BetterSignal(providing_args=["project", "event"])
 member_invited = BetterSignal(providing_args=["member", "user"])
 member_joined = BetterSignal(providing_args=["member", "organization"])
 issue_tracker_used = BetterSignal(providing_args=["plugin", "project", "user"])

+ 5 - 0
tests/sentry/receivers/test_onboarding.py

@@ -13,6 +13,7 @@ from sentry.signals import (
     event_processed,
     first_event_pending,
     first_event_received,
+    first_transaction_received,
     issue_tracker_used,
     member_invited,
     member_joined,
@@ -214,6 +215,7 @@ class OrganizationOnboardingTaskTest(TestCase):
         event = self.store_event(data=event_data, project_id=project.id)
 
         first_event_received.send(project=project, event=event, sender=type(project))
+        first_transaction_received.send(project=project, event=event, sender=type(project))
 
         task = OrganizationOnboardingTask.objects.get(
             organization=project.organization,
@@ -223,6 +225,8 @@ class OrganizationOnboardingTaskTest(TestCase):
 
         assert task is not None
 
+        assert project.flags.has_transactions
+
     def test_member_invited(self):
         user = self.create_user(email="test@example.org")
         member = self.create_member(organization=self.organization, teams=[self.team], user=user)
@@ -347,6 +351,7 @@ class OrganizationOnboardingTaskTest(TestCase):
         transaction = self.store_event(data=event_data, project_id=project.id)
 
         first_event_received.send(project=project, event=transaction, sender=type(project))
+        first_transaction_received.send(project=project, event=transaction, sender=type(project))
 
         member = self.create_member(organization=self.organization, teams=[self.team], user=user)
 

+ 6 - 2
tests/sentry/receivers/test_transactions.py

@@ -71,7 +71,9 @@ class RecordFirstTransactionTest(TestCase):
         )
 
         transaction_processed.send(project=self.project, event=event, sender=type(self.project))
-        assert self.project.flags.has_transactions
+        project = Project.objects.get(id=self.project.id)
+        assert project.flags.has_transactions
+
         mock_record.assert_called_with(
             "first_transaction.sent",
             default_user_id=self.user.id,
@@ -94,4 +96,6 @@ class RecordFirstTransactionTest(TestCase):
         )
 
         transaction_processed.send(project=self.project, event=event, sender=type(self.project))
-        assert self.project.flags.has_transactions
+        project = Project.objects.get(id=self.project.id)
+
+        assert project.flags.has_transactions