Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(replays): Reject replay envelopes if any item contained within is invalid #3201

Merged

Conversation

cmanallen
Copy link
Member

Closes: #3180

Drop the envelope in its entirety if any component fails validation. This prevents confusing states where is shown a replay which was never ingested.

@cmanallen cmanallen requested a review from a team as a code owner March 4, 2024 13:53
Copy link
Member

@jjbayer jjbayer left a comment

Choose a reason for hiding this comment

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

See comment. We definitely need a few tests for this at well.

Comment on lines 133 to 137
if dropped_item {
state
.managed_envelope
.reject(Outcome::Invalid(DiscardReason::ReplayRejected));
}
Copy link
Member

Choose a reason for hiding this comment

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

This leads to different behavior depending on the order of items:

  1. If the first item is dropped with an outcome, all subsequent items are dropped silently (one outcome in total).
  2. If the second item is dropped with an outcome, the first outcome will still be in the envelope after retain_items. In that case, the first item will be rejected with ReplayRejected outcome (two outcomes in total).

Maybe we can replace retain_items with a simple for loop that breaks on the first failure, and then rejects the envelope with the outcome of the first failure.

Copy link
Member Author

Choose a reason for hiding this comment

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

@jjbayer I thought reject logged and emitted no outcomes? This is what I was referencing when writing the PR.

Handling::Success => relay_log::debug!("dropped envelope: {outcome}"),

Copy link
Member

Choose a reason for hiding this comment

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

reject does log outcomes (the Handling is only used to decide whether or not to log an error). But it turns out we don't log outcomes for replays in reject, which is probably just oversight:

if let Some(category) = self.event_category() {
self.track_outcome(outcome.clone(), category, 1);
}
if self.context.summary.attachment_quantity > 0 {
self.track_outcome(
outcome.clone(),
DataCategory::Attachment,
self.context.summary.attachment_quantity,
);
}
if self.context.summary.profile_quantity > 0 {
self.track_outcome(
outcome.clone(),
if self.use_index_category() {
DataCategory::ProfileIndexed
} else {
DataCategory::Profile
},
self.context.summary.profile_quantity,
);
}
// Track outcomes for attached secondary transactions, e.g. extracted from metrics.
//
// Primary transaction count is already tracked through the event category
// (see: `Self::event_category()`).
if self.context.summary.secondary_transaction_quantity > 0 {
self.track_outcome(
outcome,
// Secondary transaction counts are never indexed transactions
DataCategory::Transaction,
self.context.summary.secondary_transaction_quantity,
);
}

Not sure what the best way forward is here, maybe the best would be to return a ProcessingError, which is then automatically reported as an outcome via ProcessingError::to_outcome.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've added retain_or_reject_all methods to ManagedEnvelope and Envelope. It guarantees one outcome is emitted, breaks early on processing error, ensures the envelope is empty after error, and uses all of the familiar APIs replay is accustomed to.

Copy link
Member

Choose a reason for hiding this comment

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

I looked into the code some more, I'm convinced now that the cleanest way to reject an entire envelope is to raise a ProcessingError and let it bubble up, because that's API that already exists for this purpose. And to make sure that ManagedEnvelope::reject emits outcomes for replays.

For the test, you can add the outcomes_consumer fixture in existing replay integration tests for that, or add new tests in test_outcome.py.

Copy link
Member Author

Choose a reason for hiding this comment

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

@jjbayer This commit implements the ProcessingError flow 27fcc83

@iker-barriocanal
Copy link
Contributor

Is the goal to have a single outcome per replay? IIRC, in the past replays were split into two envelopes; how would outcome generation behave in that situation?

@cmanallen cmanallen requested a review from jjbayer March 6, 2024 14:05
@cmanallen
Copy link
Member Author

cmanallen commented Mar 6, 2024

@iker-barriocanal This change doesn't handle that case but its not a common path. It might not be used any more.

Copy link
Member

@jjbayer jjbayer left a comment

Choose a reason for hiding this comment

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

Nice, with some tests this should be good to go!

relay-server/src/services/processor/replay.rs Outdated Show resolved Hide resolved
relay-server/src/envelope.rs Outdated Show resolved Hide resolved
relay-server/src/services/processor/replay.rs Outdated Show resolved Hide resolved
CHANGELOG.md Outdated Show resolved Hide resolved
@cmanallen
Copy link
Member Author

@iker-barriocanal @jjbayer Adding test coverage for this. I'm seeing in the logs relay_server::utils::managed_envelope: dropped envelope: invalid data (invalid_replay) but no outcomes emitted. The reason is ManagedEnvelope.context.summary.event_category is None. How can I populate this?

@cmanallen cmanallen requested a review from jjbayer March 7, 2024 13:50
@iker-barriocanal
Copy link
Contributor

iker-barriocanal commented Mar 7, 2024

@cmanallen Relay doesn't infer event categories for replays, see

ItemType::ReplayEvent => None,
ItemType::ReplayRecording => None,
ItemType::ReplayVideo => None,

I believe updating the applicable cases should populate the envelope context.
Edit: actually, this could have bad side-effects.

@cmanallen
Copy link
Member Author

@iker-barriocanal I updated those locally and it didn't change the test failure :\

@jjbayer
Copy link
Member

jjbayer commented Mar 8, 2024

@cmanallen I added the missing replay rejection to ManagedEnvelope::reject and pushed a commit!

The quantity of the outcome will still be the number of items, because that is consistent with how we count replays for rate limiting purposes.

@cmanallen
Copy link
Member Author

@jjbayer Updated test coverage and changed quantity to only emit one outcome. This should be ready.

relay-server/src/utils/rate_limits.rs Outdated Show resolved Hide resolved
relay-server/src/utils/managed_envelope.rs Outdated Show resolved Hide resolved
@cmanallen cmanallen merged commit 87b23e6 into master Mar 8, 2024
20 checks passed
@cmanallen cmanallen deleted the cmanallen/replays-drop-envelope-if-any-item-is-invalid branch March 8, 2024 14:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Drop replay evelope if any of the items fails validation
3 participants