Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 2 additions & 12 deletions src/sentry/profiles/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,18 +244,8 @@ def process_profile_task(
except Exception as e:
sentry_sdk.capture_exception(e)

if (
features.has("projects:continuous-profiling-vroomrs-processing", project)
and "profiler_id" in profile
) or (
features.has("projects:transaction-profiling-vroomrs-processing", project)
and ("event_id" in profile or "profile_id" in profile)
):
if not _process_vroomrs_profile(profile, project):
return
else:
if not _push_profile_to_vroom(profile, project):
return
if not _process_vroomrs_profile(profile, project):
return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Profile Processing Fails Without Chunk Handling

The change unconditionally calls _process_vroomrs_profile() without the previous feature flag guards. However, _process_vroomrs_profile() has a critical flaw: if a profile doesn't have "profiler_id", "event_id", or "profile_id", it will call _track_failed_outcome() with reason "profiling_failed_vroomrs_processing" and return False, causing the profile to be rejected. The old code had a fallback to _push_profile_to_vroom() for profiles not matching the vroomrs processing conditions. Profiles with only "chunk_id" but not "profiler_id" would fall through to the failure case, when they should be handled by the fallback or vroomrs functions that support chunk processing.

Fix in Cursor Fix in Web


if sampled:
with metrics.timer("process_profile.track_outcome.accepted"):
Expand Down
58 changes: 32 additions & 26 deletions tests/sentry/profiles/test_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -847,14 +847,14 @@ def test_set_frames_platform_android() -> None:
@patch("sentry.profiles.task._track_duration_outcome")
@patch("sentry.profiles.task._symbolicate_profile")
@patch("sentry.profiles.task._deobfuscate_profile")
@patch("sentry.profiles.task._push_profile_to_vroom")
@patch("sentry.profiles.task._process_vroomrs_profile")
@django_db_all
@pytest.mark.parametrize(
"profile",
["sample_v1_profile", "sample_v2_profile"],
)
def test_process_profile_task_should_emit_profile_duration_outcome(
_push_profile_to_vroom,
_process_vroomrs_profile,
_deobfuscate_profile,
_symbolicate_profile,
_track_duration_outcome,
Expand All @@ -864,7 +864,7 @@ def test_process_profile_task_should_emit_profile_duration_outcome(
project,
request,
):
_push_profile_to_vroom.return_value = True
_process_vroomrs_profile.return_value = True
_deobfuscate_profile.return_value = True
_symbolicate_profile.return_value = True

Expand Down Expand Up @@ -893,14 +893,14 @@ def test_process_profile_task_should_emit_profile_duration_outcome(
@patch("sentry.profiles.task._track_duration_outcome")
@patch("sentry.profiles.task._symbolicate_profile")
@patch("sentry.profiles.task._deobfuscate_profile")
@patch("sentry.profiles.task._push_profile_to_vroom")
@patch("sentry.profiles.task._process_vroomrs_profile")
@django_db_all
@pytest.mark.parametrize(
"profile",
["sample_v1_profile", "sample_v2_profile"],
)
def test_process_profile_task_should_not_emit_profile_duration_outcome(
_push_profile_to_vroom,
_process_vroomrs_profile,
_deobfuscate_profile,
_symbolicate_profile,
_track_duration_outcome,
Expand All @@ -911,7 +911,7 @@ def test_process_profile_task_should_not_emit_profile_duration_outcome(
project,
request,
):
_push_profile_to_vroom.return_value = True
_process_vroomrs_profile.return_value = True
_deobfuscate_profile.return_value = True
_symbolicate_profile.return_value = True
should_emit_profile_duration_outcome.return_value = False
Expand Down Expand Up @@ -941,7 +941,7 @@ def test_process_profile_task_should_not_emit_profile_duration_outcome(
assert _track_outcome.call_count == 0


@patch("sentry.profiles.task._push_profile_to_vroom")
@patch("sentry.profiles.task._process_vroomrs_profile")
@patch("sentry.profiles.task._symbolicate_profile")
@patch("sentry.models.projectsdk.get_sdk_index")
@pytest.mark.parametrize(
Expand All @@ -955,14 +955,14 @@ def test_process_profile_task_should_not_emit_profile_duration_outcome(
def test_track_latest_sdk(
get_sdk_index,
_symbolicate_profile,
_push_profile_to_vroom,
_process_vroomrs_profile,
profile,
event_type,
organization,
project,
request,
):
_push_profile_to_vroom.return_value = True
_process_vroomrs_profile.return_value = True
_symbolicate_profile.return_value = True
get_sdk_index.return_value = {
"sentry.python": {},
Expand All @@ -986,7 +986,7 @@ def test_track_latest_sdk(
)


@patch("sentry.profiles.task._push_profile_to_vroom")
@patch("sentry.profiles.task._process_vroomrs_profile")
@patch("sentry.profiles.task._symbolicate_profile")
@patch("sentry.models.projectsdk.get_sdk_index")
@pytest.mark.parametrize(
Expand All @@ -1001,14 +1001,14 @@ def test_track_latest_sdk(
def test_unknown_sdk(
get_sdk_index,
_symbolicate_profile,
_push_profile_to_vroom,
_process_vroomrs_profile,
platform,
sdk_name,
organization,
project,
request,
):
_push_profile_to_vroom.return_value = True
_process_vroomrs_profile.return_value = True
_symbolicate_profile.return_value = True
get_sdk_index.return_value = {
sdk_name: {},
Expand All @@ -1034,19 +1034,19 @@ def test_unknown_sdk(
)


@patch("sentry.profiles.task._push_profile_to_vroom")
@patch("sentry.profiles.task._process_vroomrs_profile")
@patch("sentry.profiles.task._symbolicate_profile")
@patch("sentry.models.projectsdk.get_sdk_index")
@django_db_all
def test_track_latest_sdk_with_payload(
get_sdk_index: Any,
_symbolicate_profile: Any,
_push_profile_to_vroom: Any,
_process_vroomrs_profile: Any,
organization: Organization,
project: Project,
request: Any,
) -> None:
_push_profile_to_vroom.return_value = True
_process_vroomrs_profile.return_value = True
_symbolicate_profile.return_value = True
get_sdk_index.return_value = {
"sentry.python": {},
Expand Down Expand Up @@ -1078,8 +1078,9 @@ def test_track_latest_sdk_with_payload(
)


@patch("sentry.profiles.task._symbolicate_profile")
@patch("sentry.profiles.task._track_outcome")
@patch("sentry.profiles.task._push_profile_to_vroom")
@patch("sentry.profiles.task._process_vroomrs_profile")
@django_db_all
@pytest.mark.parametrize(
["profile", "category", "sdk_version", "dropped"],
Expand All @@ -1091,8 +1092,9 @@ def test_track_latest_sdk_with_payload(
],
)
def test_deprecated_sdks(
_push_profile_to_vroom,
_process_vroomrs_profile,
_track_outcome,
_symbolicate_profile: mock.MagicMock,
profile,
category,
sdk_version,
Expand All @@ -1108,6 +1110,7 @@ def test_deprecated_sdks(
"name": "sentry.python",
"version": sdk_version,
}
_symbolicate_profile.return_value = True

with Feature(
[
Expand All @@ -1124,7 +1127,7 @@ def test_deprecated_sdks(
process_profile_task(profile=profile)

if dropped:
_push_profile_to_vroom.assert_not_called()
_process_vroomrs_profile.assert_not_called()
_track_outcome.assert_called_with(
profile=profile,
project=project,
Expand All @@ -1133,11 +1136,12 @@ def test_deprecated_sdks(
reason="deprecated sdk",
)
else:
_push_profile_to_vroom.assert_called()
_process_vroomrs_profile.assert_called()


@patch("sentry.profiles.task._symbolicate_profile")
@patch("sentry.profiles.task._track_outcome")
@patch("sentry.profiles.task._push_profile_to_vroom")
@patch("sentry.profiles.task._process_vroomrs_profile")
@django_db_all
@pytest.mark.parametrize(
["profile", "category", "sdk_version", "dropped"],
Expand All @@ -1149,8 +1153,9 @@ def test_deprecated_sdks(
],
)
def test_rejected_sdks(
_push_profile_to_vroom,
_process_vroomrs_profile,
_track_outcome,
_symbolicate_profile: mock.MagicMock,
profile,
category,
sdk_version,
Expand All @@ -1166,6 +1171,7 @@ def test_rejected_sdks(
"name": "sentry.cocoa",
"version": sdk_version,
}
_symbolicate_profile.return_value = True

with Feature(
[
Expand All @@ -1185,7 +1191,7 @@ def test_rejected_sdks(
process_profile_task(profile=profile)

if dropped:
_push_profile_to_vroom.assert_not_called()
_process_vroomrs_profile.assert_not_called()
_track_outcome.assert_called_with(
profile=profile,
project=project,
Expand All @@ -1194,19 +1200,19 @@ def test_rejected_sdks(
reason="rejected sdk",
)
else:
_push_profile_to_vroom.assert_called()
_process_vroomrs_profile.assert_called()


@patch("sentry.profiles.task._symbolicate_profile")
@patch("sentry.profiles.task._deobfuscate_profile")
@patch("sentry.profiles.task._push_profile_to_vroom")
@patch("sentry.profiles.task._process_vroomrs_profile")
@django_db_all
@pytest.mark.parametrize(
"profile",
["sample_v1_profile", "sample_v2_profile"],
)
def test_process_profile_task_should_flip_project_flag(
_push_profile_to_vroom: mock.MagicMock,
_process_vroomrs_profile: mock.MagicMock,
_deobfuscate_profile: mock.MagicMock,
_symbolicate_profile: mock.MagicMock,
profile,
Expand All @@ -1218,7 +1224,7 @@ def test_process_profile_task_should_flip_project_flag(
"sentry.receivers.onboarding.record_first_profile",
) as mock_record_first_profile:
first_profile_received.connect(mock_record_first_profile, weak=False)
_push_profile_to_vroom.return_value = True
_process_vroomrs_profile.return_value = True
_deobfuscate_profile.return_value = True
_symbolicate_profile.return_value = True

Expand Down
Loading