Skip to content

Commit ac4a5f8

Browse files
committed
Fix
1 parent b36d343 commit ac4a5f8

File tree

6 files changed

+42
-26
lines changed

6 files changed

+42
-26
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

relay-threading/Cargo.toml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,21 @@ authors = ["Sentry <[email protected]>"]
44
description = "Threading code that is used by Relay"
55
homepage = "https://getsentry.github.io/relay/"
66
repository = "https://github.com/getsentry/relay"
7-
version = "25.1.0"
7+
version = "25.2.0"
88
edition = "2021"
99
license-file = "../LICENSE.md"
1010
publish = false
1111

1212
[dependencies]
13-
flume = { workspace = true }
14-
futures = { workspace = true, features = ["executor"] }
15-
tokio = { workspace = true, features = ["rt", "rt-multi-thread", "time", "sync", "macros"] }
13+
flume = { workspace = true, default-features = false }
14+
futures = { workspace = true, default-features = false }
15+
tokio = { workspace = true }
1616
pin-project-lite = { workspace = true }
1717

1818
[dev-dependencies]
1919
criterion = { workspace = true, features = ["async_tokio"] }
20+
futures = { workspace = true, default-features = false, features = ["executor"] }
21+
tokio = { workspace = true, features = ["rt", "rt-multi-thread", "time", "sync", "macros"] }
2022

2123
[[bench]]
2224
name = "pool"

relay-threading/src/builder.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ use std::sync::Arc;
66
use crate::pool::{AsyncPool, Thread};
77
use crate::pool::{CustomSpawn, DefaultSpawn, ThreadSpawn};
88

9+
/// Type alias for a thread safe closure that is used for panic handling across the code.
10+
pub(crate) type PanicHandler = dyn Fn(Box<dyn Any + Send>) + Send + Sync;
11+
912
/// [`AsyncPoolBuilder`] provides a flexible way to configure and build an [`AsyncPool`] for executing
1013
/// asynchronous tasks concurrently on dedicated threads.
1114
///
@@ -14,10 +17,8 @@ use crate::pool::{CustomSpawn, DefaultSpawn, ThreadSpawn};
1417
pub struct AsyncPoolBuilder<S = DefaultSpawn> {
1518
pub(crate) runtime: tokio::runtime::Handle,
1619
pub(crate) thread_name: Option<Box<dyn FnMut(usize) -> String>>,
17-
#[allow(clippy::type_complexity)]
18-
pub(crate) thread_panic_handler: Option<Arc<dyn Fn(Box<dyn Any + Send>) + Send + Sync>>,
19-
#[allow(clippy::type_complexity)]
20-
pub(crate) task_panic_handler: Option<Arc<dyn Fn(Box<dyn Any + Send>) + Send + Sync>>,
20+
pub(crate) thread_panic_handler: Option<Arc<PanicHandler>>,
21+
pub(crate) task_panic_handler: Option<Arc<PanicHandler>>,
2122
pub(crate) spawn_handler: S,
2223
pub(crate) num_threads: usize,
2324
pub(crate) max_concurrency: usize,

relay-threading/src/multiplexing.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use std::any::Any;
21
use std::future::Future;
32
use std::panic::AssertUnwindSafe;
43
use std::pin::Pin;
54
use std::sync::Arc;
65
use std::task::{Context, Poll};
76

7+
use crate::PanicHandler;
88
use futures::future::CatchUnwind;
99
use futures::stream::{FusedStream, FuturesUnordered, Stream};
1010
use futures::FutureExt;
@@ -19,16 +19,15 @@ pin_project! {
1919
struct Tasks<F> {
2020
#[pin]
2121
futures: FuturesUnordered<Unconstrained<CatchUnwind<AssertUnwindSafe<F>>>>,
22-
panic_handler: Option<Arc<dyn Fn(Box<dyn Any + Send>) + Send + Sync>>,
22+
panic_handler: Option<Arc<PanicHandler>>,
2323
}
2424
}
2525

2626
impl<F> Tasks<F> {
2727
/// Creates a new task manager.
2828
///
2929
/// This internal constructor initializes a new collection for tracking asynchronous tasks.
30-
#[allow(clippy::type_complexity)]
31-
fn new(panic_handler: Option<Arc<dyn Fn(Box<dyn Any + Send>) + Send + Sync>>) -> Self {
30+
fn new(panic_handler: Option<Arc<PanicHandler>>) -> Self {
3231
Self {
3332
futures: FuturesUnordered::new(),
3433
panic_handler,
@@ -118,12 +117,8 @@ where
118117
///
119118
/// Tasks from the stream will be scheduled for execution concurrently, and an optional panic handler
120119
/// can be provided to manage errors during task execution.
121-
#[allow(clippy::type_complexity)]
122-
pub fn new(
123-
max_concurrency: usize,
124-
rx: S,
125-
panic_handler: Option<Arc<dyn Fn(Box<dyn Any + Send>) + Send + Sync>>,
126-
) -> Self {
120+
121+
pub fn new(max_concurrency: usize, rx: S, panic_handler: Option<Arc<PanicHandler>>) -> Self {
127122
Self {
128123
max_concurrency,
129124
rx,

relay-threading/src/pool.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::any::Any;
21
use std::future::Future;
32
use std::io;
43
use std::panic::AssertUnwindSafe;
@@ -9,6 +8,7 @@ use futures::FutureExt;
98

109
use crate::builder::AsyncPoolBuilder;
1110
use crate::multiplexing::Multiplexed;
11+
use crate::PanicHandler;
1212

1313
/// [`AsyncPool`] is a thread-based executor that runs asynchronous tasks on dedicated worker threads.
1414
///
@@ -67,11 +67,12 @@ where
6767
///
6868
/// # Panics
6969
///
70-
/// This method panics if the internal task channel is unexpectedly closed.
70+
/// This method panics if all receivers have been dropped which can happen when all threads of
71+
/// the pool panicked.
7172
pub fn spawn(&self, future: F) {
7273
assert!(
7374
self.tx.send(future).is_ok(),
74-
"receiver never exits before sender"
75+
"failed to schedule task: all worker threads have terminated (either none were spawned or all have panicked)"
7576
);
7677
}
7778

@@ -81,11 +82,12 @@ where
8182
///
8283
/// # Panics
8384
///
84-
/// This method panics if the internal task channel is unexpectedly closed.
85+
/// This method panics if all receivers have been dropped which can happen when all threads of
86+
/// the pool panicked.
8587
pub async fn spawn_async(&self, future: F) {
8688
assert!(
8789
self.tx.send_async(future).await.is_ok(),
88-
"receiver never exits before sender"
90+
"failed to schedule task: all worker threads have terminated (either none were spawned or all have panicked)"
8991
);
9092
}
9193
}
@@ -96,8 +98,7 @@ pub struct Thread {
9698
max_concurrency: usize,
9799
name: Option<String>,
98100
runtime: tokio::runtime::Handle,
99-
#[allow(clippy::type_complexity)]
100-
panic_handler: Option<Arc<dyn Fn(Box<dyn Any + Send>) + Send + Sync>>,
101+
panic_handler: Option<Arc<PanicHandler>>,
101102
task: BoxFuture<'static, ()>,
102103
}
103104

@@ -206,6 +207,7 @@ where
206207
#[cfg(test)]
207208
mod tests {
208209
use std::future::Future;
210+
use std::panic::AssertUnwindSafe;
209211
use std::sync::atomic::AtomicBool;
210212
use std::sync::{
211213
atomic::{AtomicUsize, Ordering},
@@ -368,4 +370,19 @@ mod tests {
368370

369371
assert!(has_panicked.load(Ordering::SeqCst));
370372
}
373+
374+
#[tokio::test]
375+
async fn test_spawn_panics_if_no_threads_are_available() {
376+
let pool = AsyncPoolBuilder::new(Handle::current())
377+
.num_threads(0)
378+
.max_concurrency(1)
379+
.build()
380+
.unwrap();
381+
382+
let result = std::panic::catch_unwind(AssertUnwindSafe(|| {
383+
pool.spawn(async move {});
384+
}));
385+
386+
assert!(result.is_err());
387+
}
371388
}

relay/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
//! - [`relay-statsd`]: High-level StatsD metric client for internal measurements.
6464
//! - [`relay-system`]: Foundational system components for Relay's services.
6565
//! - [`relay-test`]: Helpers for testing the web server and services.
66+
//! - [`relay-threading`]: Threading code that is used by Relay.
6667
//! - [`relay-ua`]: User agent parser with built-in rules.
6768
//!
6869
//! # Tools

0 commit comments

Comments
 (0)