From 86aca49f6533c25aa60c7c0330324ae63475e12d Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Wed, 29 Apr 2026 17:27:55 +0200 Subject: [PATCH 1/3] fix(eap-outcomes): Add trace ID and timestmap to dedup key ref STREAM-881 --- .../src/strategies/accepted_outcomes/aggregator.rs | 12 ++++++++++++ rust_snuba/src/types.rs | 6 +++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/rust_snuba/src/strategies/accepted_outcomes/aggregator.rs b/rust_snuba/src/strategies/accepted_outcomes/aggregator.rs index 1b67935122..a4910588e0 100644 --- a/rust_snuba/src/strategies/accepted_outcomes/aggregator.rs +++ b/rust_snuba/src/strategies/accepted_outcomes/aggregator.rs @@ -91,10 +91,22 @@ impl OutcomesAggregator { let item_type = TraceItemType::try_from(trace_item.item_type).unwrap_or(TraceItemType::Unspecified); + let timestamp = trace_item + .timestamp + .as_ref() + .map(|t| t.seconds as u32) + .unwrap_or(0); + + let trace_id = uuid::Uuid::try_parse(&trace_item.trace_id) + .map(|u| *u.as_bytes()) + .unwrap_or([0u8; 16]); + if let Ok(item_id) = <[u8; 16]>::try_from(trace_item.item_id.as_slice()) { let dedup_key = ItemDedupKey { org_id, project_id, + timestamp, + trace_id, item_id, }; return self.batch.record_if_duplicate(item_type, dedup_key); diff --git a/rust_snuba/src/types.rs b/rust_snuba/src/types.rs index 1cd5d940f6..b03dc8120d 100644 --- a/rust_snuba/src/types.rs +++ b/rust_snuba/src/types.rs @@ -619,11 +619,15 @@ pub struct TrackOutcome { } /// Key used to deduplicate items within an outcomes batch. -/// Uses the relevant fields from the eap_items table sorting key. +/// Uses the relevant fields from the eap_items table sorting key: +/// (organization_id, project_id, item_type, timestamp, trace_id, item_id) +/// Note: item_type is handled separately via the HashMap in seen_items. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ItemDedupKey { pub org_id: u64, pub project_id: u64, + pub timestamp: u32, + pub trace_id: [u8; 16], pub item_id: [u8; 16], } From a6d782a6f268ac855dff099261b87434657665c1 Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Wed, 29 Apr 2026 17:42:47 +0200 Subject: [PATCH 2/3] stop deduping for other item types --- rust_snuba/src/strategies/accepted_outcomes/aggregator.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rust_snuba/src/strategies/accepted_outcomes/aggregator.rs b/rust_snuba/src/strategies/accepted_outcomes/aggregator.rs index a4910588e0..a4b50eb8cf 100644 --- a/rust_snuba/src/strategies/accepted_outcomes/aggregator.rs +++ b/rust_snuba/src/strategies/accepted_outcomes/aggregator.rs @@ -91,6 +91,10 @@ impl OutcomesAggregator { let item_type = TraceItemType::try_from(trace_item.item_type).unwrap_or(TraceItemType::Unspecified); + if item_type != TraceItemType::Span { + return false; + } + let timestamp = trace_item .timestamp .as_ref() From cd3d18b4bf3780092bd834312c500fd7b165057c Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Wed, 29 Apr 2026 18:24:53 +0200 Subject: [PATCH 3/3] fix(eap-outcomes): Set item_type in test helper to fix dedup tests The make_payload_with_item_id test helper was using Default for item_type (Unspecified), but the new Span-only guard requires item_type to be Span for deduplication to occur. Co-Authored-By: Claude Opus 4.5 --- rust_snuba/src/strategies/accepted_outcomes/aggregator.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rust_snuba/src/strategies/accepted_outcomes/aggregator.rs b/rust_snuba/src/strategies/accepted_outcomes/aggregator.rs index a4b50eb8cf..c1c21897af 100644 --- a/rust_snuba/src/strategies/accepted_outcomes/aggregator.rs +++ b/rust_snuba/src/strategies/accepted_outcomes/aggregator.rs @@ -798,6 +798,7 @@ mod tests { organization_id: org_id, project_id, item_id: item_id.to_vec(), + item_type: TraceItemType::Span.into(), received: Some(Timestamp { seconds: ts_secs, nanos: 0,