Skip to content

Commit 0414b84

Browse files
authored
fix: Explicitly drop SessionFlusher (#326)
It seems that doing a thread::join from within the Drop impl of a thread local THREAD_HUB will deadlock for some reason. Explicitly joining the background flusher as part of the ClientGuard Drop does work, and is also more correct, as otherwise the PROCESS_HUB might keep the worker alive forever.
1 parent f86a4db commit 0414b84

File tree

4 files changed

+33
-8
lines changed

4 files changed

+33
-8
lines changed

Diff for: sentry-core/src/client.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub(crate) type TransportArc = Arc<RwLock<Option<Arc<dyn Transport>>>>;
4343
pub struct Client {
4444
options: ClientOptions,
4545
transport: TransportArc,
46-
session_flusher: SessionFlusher,
46+
session_flusher: RwLock<Option<SessionFlusher>>,
4747
integrations: Vec<(TypeId, Arc<dyn Integration>)>,
4848
sdk_info: ClientSdkInfo,
4949
}
@@ -60,7 +60,10 @@ impl fmt::Debug for Client {
6060
impl Clone for Client {
6161
fn clone(&self) -> Client {
6262
let transport = Arc::new(RwLock::new(self.transport.read().unwrap().clone()));
63-
let session_flusher = SessionFlusher::new(transport.clone(), self.options.session_mode);
63+
let session_flusher = RwLock::new(Some(SessionFlusher::new(
64+
transport.clone(),
65+
self.options.session_mode,
66+
)));
6467
Client {
6568
options: self.options.clone(),
6669
transport,
@@ -128,7 +131,10 @@ impl Client {
128131
sdk_info.integrations.push(integration.name().to_string());
129132
}
130133

131-
let session_flusher = SessionFlusher::new(transport.clone(), options.session_mode);
134+
let session_flusher = RwLock::new(Some(SessionFlusher::new(
135+
transport.clone(),
136+
options.session_mode,
137+
)));
132138
Client {
133139
options,
134140
transport,
@@ -287,12 +293,16 @@ impl Client {
287293
}
288294

289295
pub(crate) fn enqueue_session(&self, session_update: SessionUpdate<'static>) {
290-
self.session_flusher.enqueue(session_update)
296+
if let Some(ref flusher) = *self.session_flusher.read().unwrap() {
297+
flusher.enqueue(session_update);
298+
}
291299
}
292300

293301
/// Drains all pending events without shutting down.
294302
pub fn flush(&self, timeout: Option<Duration>) -> bool {
295-
self.session_flusher.flush();
303+
if let Some(ref flusher) = *self.session_flusher.read().unwrap() {
304+
flusher.flush();
305+
}
296306
if let Some(ref transport) = *self.transport.read().unwrap() {
297307
transport.flush(timeout.unwrap_or(self.options.shutdown_timeout))
298308
} else {
@@ -308,7 +318,7 @@ impl Client {
308318
/// If no timeout is provided the client will wait for as long a
309319
/// `shutdown_timeout` in the client options.
310320
pub fn close(&self, timeout: Option<Duration>) -> bool {
311-
self.session_flusher.flush();
321+
drop(self.session_flusher.write().unwrap().take());
312322
let transport_opt = self.transport.write().unwrap().take();
313323
if let Some(transport) = transport_opt {
314324
sentry_debug!("client close; request transport to shut down");

Diff for: sentry-core/src/hub.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ impl Hub {
156156
f(&PROCESS_HUB.0)
157157
} else {
158158
// note on safety: this is safe because even though we change the Arc
159-
// by temorary binding we guarantee that the original Arc stays alive.
159+
// by temporary binding we guarantee that the original Arc stays alive.
160160
// For more information see: run
161161
THREAD_HUB.with(|stack| unsafe {
162162
let ptr = stack.get();

Diff for: sentry/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ log_ = { package = "log", version = "0.4.8", optional = true, features = ["std"]
5151
reqwest_ = { package = "reqwest", version = "0.11", optional = true, features = ["blocking", "json"], default-features = false }
5252
curl_ = { package = "curl", version = "0.4.25", optional = true }
5353
surf_ = { package = "surf", version = "2.0.0", optional = true }
54-
httpdate = { version = "0.3.2", optional = true }
54+
httpdate = { version = "1.0.0", optional = true }
5555
serde_json = { version = "1.0.48", optional = true }
5656
tokio = { version = "1.0", features = ["rt"] }
5757

Diff for: sentry/tests/test_client.rs

+15
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,18 @@ fn test_unwind_safe() {
5656

5757
assert_eq!(events.len(), 1);
5858
}
59+
60+
#[test]
61+
fn test_concurrent_init() {
62+
let _guard = sentry::init(sentry::ClientOptions {
63+
..Default::default()
64+
});
65+
66+
std::thread::spawn(|| {
67+
let _guard = sentry::init(sentry::ClientOptions {
68+
..Default::default()
69+
});
70+
})
71+
.join()
72+
.unwrap();
73+
}

0 commit comments

Comments
 (0)