diff --git a/sentry-core/src/client.rs b/sentry-core/src/client.rs index c62b930d..346a8dea 100644 --- a/sentry-core/src/client.rs +++ b/sentry-core/src/client.rs @@ -43,7 +43,7 @@ pub(crate) type TransportArc = Arc>>>; pub struct Client { options: ClientOptions, transport: TransportArc, - session_flusher: SessionFlusher, + session_flusher: RwLock>, integrations: Vec<(TypeId, Arc)>, sdk_info: ClientSdkInfo, } @@ -60,7 +60,10 @@ impl fmt::Debug for Client { impl Clone for Client { fn clone(&self) -> Client { let transport = Arc::new(RwLock::new(self.transport.read().unwrap().clone())); - let session_flusher = SessionFlusher::new(transport.clone(), self.options.session_mode); + let session_flusher = RwLock::new(Some(SessionFlusher::new( + transport.clone(), + self.options.session_mode, + ))); Client { options: self.options.clone(), transport, @@ -128,7 +131,10 @@ impl Client { sdk_info.integrations.push(integration.name().to_string()); } - let session_flusher = SessionFlusher::new(transport.clone(), options.session_mode); + let session_flusher = RwLock::new(Some(SessionFlusher::new( + transport.clone(), + options.session_mode, + ))); Client { options, transport, @@ -287,12 +293,16 @@ impl Client { } pub(crate) fn enqueue_session(&self, session_update: SessionUpdate<'static>) { - self.session_flusher.enqueue(session_update) + if let Some(ref flusher) = *self.session_flusher.read().unwrap() { + flusher.enqueue(session_update); + } } /// Drains all pending events without shutting down. pub fn flush(&self, timeout: Option) -> bool { - self.session_flusher.flush(); + if let Some(ref flusher) = *self.session_flusher.read().unwrap() { + flusher.flush(); + } if let Some(ref transport) = *self.transport.read().unwrap() { transport.flush(timeout.unwrap_or(self.options.shutdown_timeout)) } else { @@ -308,7 +318,7 @@ impl Client { /// If no timeout is provided the client will wait for as long a /// `shutdown_timeout` in the client options. pub fn close(&self, timeout: Option) -> bool { - self.session_flusher.flush(); + drop(self.session_flusher.write().unwrap().take()); let transport_opt = self.transport.write().unwrap().take(); if let Some(transport) = transport_opt { sentry_debug!("client close; request transport to shut down"); diff --git a/sentry-core/src/hub.rs b/sentry-core/src/hub.rs index bcd3ba20..27461d8c 100644 --- a/sentry-core/src/hub.rs +++ b/sentry-core/src/hub.rs @@ -156,7 +156,7 @@ impl Hub { f(&PROCESS_HUB.0) } else { // note on safety: this is safe because even though we change the Arc - // by temorary binding we guarantee that the original Arc stays alive. + // by temporary binding we guarantee that the original Arc stays alive. // For more information see: run THREAD_HUB.with(|stack| unsafe { let ptr = stack.get(); diff --git a/sentry/Cargo.toml b/sentry/Cargo.toml index eb85ccde..6c2b2cb2 100644 --- a/sentry/Cargo.toml +++ b/sentry/Cargo.toml @@ -51,7 +51,7 @@ log_ = { package = "log", version = "0.4.8", optional = true, features = ["std"] reqwest_ = { package = "reqwest", version = "0.11", optional = true, features = ["blocking", "json"], default-features = false } curl_ = { package = "curl", version = "0.4.25", optional = true } surf_ = { package = "surf", version = "2.0.0", optional = true } -httpdate = { version = "0.3.2", optional = true } +httpdate = { version = "1.0.0", optional = true } serde_json = { version = "1.0.48", optional = true } tokio = { version = "1.0", features = ["rt"] } diff --git a/sentry/tests/test_client.rs b/sentry/tests/test_client.rs index c576be95..984317c4 100644 --- a/sentry/tests/test_client.rs +++ b/sentry/tests/test_client.rs @@ -56,3 +56,18 @@ fn test_unwind_safe() { assert_eq!(events.len(), 1); } + +#[test] +fn test_concurrent_init() { + let _guard = sentry::init(sentry::ClientOptions { + ..Default::default() + }); + + std::thread::spawn(|| { + let _guard = sentry::init(sentry::ClientOptions { + ..Default::default() + }); + }) + .join() + .unwrap(); +}