Skip to content

Commit c90e360

Browse files
committed
Merge branch 'master' into doc/intra-doc-links
* master: ref(server): Remove legacy id fallback (#800)
2 parents 478659d + 549b60b commit c90e360

File tree

13 files changed

+190
-353
lines changed

13 files changed

+190
-353
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
**Internal**:
1818

1919
- Project states are now cached separately per DSN public key instead of per project ID. This means that there will be multiple separate cache entries for projects with more than one DSN. ([#778](https://github.com/getsentry/relay/pull/778))
20+
- Relay no longer uses the Sentry endpoint to resolve project IDs by public key. Ingestion for the legacy store endpoint has been refactored to rely on key-based caches only. As a result, the legacy endpoint is supported only on managed Relays. ([#800](https://github.com/getsentry/relay/pull/800))
2021

2122
## 20.9.0
2223

relay-common/src/project.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::borrow::Cow;
22
use std::fmt;
3+
use std::str::FromStr;
34

45
use serde::{Deserialize, Serialize};
56

@@ -75,3 +76,11 @@ impl fmt::Display for ProjectKey {
7576
self.as_str().fmt(f)
7677
}
7778
}
79+
80+
impl FromStr for ProjectKey {
81+
type Err = ParseProjectKeyError;
82+
83+
fn from_str(s: &str) -> Result<Self, Self::Err> {
84+
Self::parse(s)
85+
}
86+
}

relay-server/src/actors/events.rs

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use futures::prelude::*;
1212
use parking_lot::RwLock;
1313
use serde_json::Value as SerdeValue;
1414

15-
use relay_common::{clone, metric, LogError};
15+
use relay_common::{clone, metric, LogError, ProjectId};
1616
use relay_config::{Config, HttpEncoding, RelayMode};
1717
use relay_general::pii::{PiiAttachmentsProcessor, PiiProcessor};
1818
use relay_general::processor::{process_value, ProcessingState};
@@ -92,6 +92,9 @@ enum ProcessingError {
9292
#[fail(display = "failed to resolve project information")]
9393
ProjectFailed(#[cause] ProjectError),
9494

95+
#[fail(display = "missing project id in DSN")]
96+
MissingProjectId,
97+
9598
#[fail(display = "invalid security report type")]
9699
InvalidSecurityType,
97100

@@ -154,7 +157,8 @@ impl ProcessingError {
154157
| Self::ScheduleFailed(_)
155158
| Self::ProjectFailed(_)
156159
| Self::Timeout
157-
| Self::ProcessingFailed(_) => Some(Outcome::Invalid(DiscardReason::Internal)),
160+
| Self::ProcessingFailed(_)
161+
| Self::MissingProjectId => Some(Outcome::Invalid(DiscardReason::Internal)),
158162
#[cfg(feature = "processing")]
159163
Self::StoreFailed(_) | Self::QuotasFailed(_) => {
160164
Some(Outcome::Invalid(DiscardReason::Internal))
@@ -201,6 +205,13 @@ struct ProcessEnvelopeState {
201205
/// The state of the project that this envelope belongs to.
202206
project_state: Arc<ProjectState>,
203207

208+
/// The id of the project that this envelope is ingested into.
209+
///
210+
/// This identifier can differ from the one stated in the Envelope's DSN if the key was moved to
211+
/// a new project or on the legacy endpoint. In that case, normalization will update the project
212+
/// ID.
213+
project_id: ProjectId,
214+
204215
/// UTC date time converted from the `start_time` instant.
205216
received_at: DateTime<Utc>,
206217
}
@@ -283,8 +294,8 @@ impl EventProcessor {
283294
fn process_sessions(&self, state: &mut ProcessEnvelopeState) -> Result<(), ProcessingError> {
284295
let envelope = &mut state.envelope;
285296
let received = state.received_at;
297+
let project_id = state.project_id;
286298

287-
let project_id = envelope.meta().project_id().value();
288299
let clock_drift_processor =
289300
ClockDriftProcessor::new(envelope.sent_at(), received).at_least(MINIMUM_CLOCK_DRIFT);
290301
let client = envelope.meta().client().map(str::to_owned);
@@ -383,12 +394,30 @@ impl EventProcessor {
383394
envelope.set_retention(retention);
384395
}
385396

397+
// Prefer the project's project ID, and fall back to the stated project id from the
398+
// envelope. The project ID is available in all modes, other than in proxy mode, where
399+
// events for unknown projects are forwarded blindly.
400+
//
401+
// Neither ID can be available in proxy mode on the /store/ endpoint. This is not supported,
402+
// since we cannot process an event without project ID, so drop it.
403+
let project_id = project_state
404+
.project_id
405+
.or_else(|| envelope.meta().project_id())
406+
.ok_or(ProcessingError::MissingProjectId)?;
407+
408+
// Ensure the project ID is updated to the stored instance for this project cache. This can
409+
// differ in two cases:
410+
// 1. The envelope was sent to the legacy `/store/` endpoint without a project ID.
411+
// 2. The DSN was moved and the envelope sent to the old project ID.
412+
envelope.meta_mut().set_project_id(project_id);
413+
386414
Ok(ProcessEnvelopeState {
387415
envelope,
388416
event: Annotated::empty(),
389417
metrics: Metrics::default(),
390418
rate_limits: RateLimits::new(),
391419
project_state,
420+
project_id,
392421
received_at: relay_common::instant_to_date_time(start_time),
393422
})
394423
}
@@ -885,7 +914,7 @@ impl EventProcessor {
885914
}
886915

887916
let store_config = StoreConfig {
888-
project_id: Some(envelope.meta().project_id().value()),
917+
project_id: Some(state.project_id.value()),
889918
client_ip: envelope.meta().client_addr().map(IpAddr::from),
890919
client: envelope.meta().client().map(str::to_owned),
891920
key_id,
@@ -1361,7 +1390,6 @@ impl Handler<HandleEnvelope> for EventManager {
13611390
} = message;
13621391

13631392
let event_id = envelope.event_id();
1364-
let project_id = envelope.meta().project_id();
13651393
let remote_addr = envelope.meta().client_addr();
13661394

13671395
// Compute whether this envelope contains an event. This is used in error handling to
@@ -1371,13 +1399,15 @@ impl Handler<HandleEnvelope> for EventManager {
13711399

13721400
let scoping = Rc::new(RefCell::new(envelope.meta().get_partial_scoping()));
13731401

1374-
metric!(set(RelaySets::UniqueProjects) = project_id.value() as i64);
1375-
13761402
let future = project
13771403
.send(CheckEnvelope::fetched(envelope))
13781404
.map_err(ProcessingError::ScheduleFailed)
13791405
.and_then(|result| result.map_err(ProcessingError::ProjectFailed))
13801406
.and_then(clone!(scoping, |response| {
1407+
// Use the project id from the loaded project state to account for redirects.
1408+
let project_id = response.scoping.project_id.value();
1409+
metric!(set(RelaySets::UniqueProjects) = project_id as i64);
1410+
13811411
scoping.replace(response.scoping);
13821412

13831413
let checked = response.result.map_err(ProcessingError::EventRejected)?;
@@ -1452,6 +1482,7 @@ impl Handler<HandleEnvelope> for EventManager {
14521482
}
14531483

14541484
log::trace!("sending event to sentry endpoint");
1485+
let project_id = scoping.borrow().project_id;
14551486
let request = SendRequest::post(format!("/api/{}/envelope/", project_id)).build(
14561487
move |builder| {
14571488
// Override the `sent_at` timestamp. Since the event went through basic

relay-server/src/actors/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ pub mod healthcheck;
4646
pub mod outcome;
4747
pub mod project;
4848
pub mod project_cache;
49-
pub mod project_keys;
5049
pub mod project_local;
5150
pub mod project_upstream;
5251
pub mod relays;

relay-server/src/actors/project.rs

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,12 @@ pub struct LimitedProjectConfig {
8787
pub datascrubbing_settings: DataScrubbingConfig,
8888
}
8989

90-
/// Returns an invalid placeholder project identifier.
91-
fn default_project_id() -> ProjectId {
92-
ProjectId::new(0)
93-
}
94-
9590
/// The project state is a cached server state of a project.
9691
#[derive(Debug, Clone, Serialize, Deserialize)]
9792
#[serde(rename_all = "camelCase")]
9893
pub struct ProjectState {
9994
/// Unique identifier of this project.
100-
#[serde(default = "default_project_id")]
101-
pub project_id: ProjectId,
95+
pub project_id: Option<ProjectId>,
10296
/// The timestamp of when the state was last changed.
10397
///
10498
/// This might be `None` in some rare cases like where states
@@ -137,7 +131,7 @@ pub struct ProjectState {
137131
#[derive(Debug, Serialize)]
138132
#[serde(rename_all = "camelCase", remote = "ProjectState")]
139133
pub struct LimitedProjectState {
140-
pub project_id: ProjectId,
134+
pub project_id: Option<ProjectId>,
141135
pub last_change: Option<DateTime<Utc>>,
142136
pub disabled: bool,
143137
#[serde(with = "limited_public_key_comfigs")]
@@ -152,7 +146,7 @@ impl ProjectState {
152146
/// Project state for a missing project.
153147
pub fn missing() -> Self {
154148
ProjectState {
155-
project_id: ProjectId::new(0),
149+
project_id: None,
156150
last_change: None,
157151
disabled: true,
158152
public_keys: SmallVec::new(),
@@ -200,9 +194,9 @@ impl ProjectState {
200194

201195
/// Returns whether this state is outdated and needs to be refetched.
202196
pub fn outdated(&self, config: &Config) -> Outdated {
203-
let expiry = match self.project_id.value() {
204-
0 => config.cache_miss_expiry(),
205-
_ => config.project_cache_expiry(),
197+
let expiry = match self.project_id {
198+
None => config.cache_miss_expiry(),
199+
Some(_) => config.project_cache_expiry(),
206200
};
207201

208202
let elapsed = self.last_fetch.elapsed();
@@ -223,9 +217,13 @@ impl ProjectState {
223217
/// Returns `true` if the given project ID matches this project.
224218
///
225219
/// If the project state has not been loaded, this check is skipped because the project
226-
/// identifier is not yet known.
227-
pub fn is_valid_project_id(&self, project_id: ProjectId) -> bool {
228-
self.project_id.value() == 0 || self.project_id == project_id
220+
/// identifier is not yet known. Likewise, this check is skipped for the legacy store endpoint
221+
/// which comes without a project ID. The id is later overwritten in `check_envelope`.
222+
pub fn is_valid_project_id(&self, stated_id: Option<ProjectId>) -> bool {
223+
match (self.project_id, stated_id) {
224+
(Some(actual_id), Some(stated_id)) => actual_id == stated_id,
225+
_ => true,
226+
}
229227
}
230228

231229
/// Checks if this origin is allowed for this project.
@@ -260,7 +258,7 @@ impl ProjectState {
260258
key_config.public_key == public_key
261259
} else {
262260
// Loaded states must have a key config, but ignore missing and invalid states.
263-
self.project_id.value() == 0
261+
self.project_id.is_none()
264262
}
265263
}
266264

@@ -282,8 +280,8 @@ impl ProjectState {
282280
// The original project identifier is part of the DSN. If the DSN was moved to another
283281
// project, the actual project identifier is different and can be obtained from project
284282
// states. This is only possible when the project state has been loaded.
285-
if self.project_id.value() != 0 {
286-
scoping.project_id = self.project_id;
283+
if let Some(project_id) = self.project_id {
284+
scoping.project_id = project_id;
287285
}
288286

289287
// This is a hack covering three cases:

relay-server/src/actors/project_cache.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ pub struct FetchProjectState {
173173
pub public_key: ProjectKey,
174174
}
175175

176+
#[derive(Debug)]
176177
pub struct ProjectStateResponse {
177178
pub state: Arc<ProjectState>,
178179
pub is_local: bool,

0 commit comments

Comments
 (0)