From: Lukas Wagner <l.wagner@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [PATCH proxmox 03/26] parallel-handler: introduce custom error type
Date: Thu, 12 Mar 2026 14:52:04 +0100 [thread overview]
Message-ID: <20260312135229.420729-4-l.wagner@proxmox.com> (raw)
In-Reply-To: <20260312135229.420729-1-l.wagner@proxmox.com>
Derive a custom error type using `thiserror`. For the handler functions,
we still use anyhow::Error, since that would involve bigger changes in
the callers.
Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
---
proxmox-parallel-handler/Cargo.toml | 1 +
proxmox-parallel-handler/src/lib.rs | 67 +++++++++++++++++++----------
2 files changed, 46 insertions(+), 22 deletions(-)
diff --git a/proxmox-parallel-handler/Cargo.toml b/proxmox-parallel-handler/Cargo.toml
index e55e7c63..5fe67889 100644
--- a/proxmox-parallel-handler/Cargo.toml
+++ b/proxmox-parallel-handler/Cargo.toml
@@ -13,3 +13,4 @@ repository.workspace = true
[dependencies]
anyhow.workspace = true
crossbeam-channel.workspace = true
+thiserror.workspace = true
diff --git a/proxmox-parallel-handler/src/lib.rs b/proxmox-parallel-handler/src/lib.rs
index 75eab184..4c2ac118 100644
--- a/proxmox-parallel-handler/src/lib.rs
+++ b/proxmox-parallel-handler/src/lib.rs
@@ -3,9 +3,25 @@
use std::sync::{Arc, Mutex};
use std::thread::JoinHandle;
-use anyhow::{bail, format_err, Error};
use crossbeam_channel::{bounded, Sender};
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+ #[error("send failed - channel closed")]
+ ChannelClosed,
+
+ #[error("handler failed: {0}")]
+ HandlerFailed(String),
+
+ #[error("thread {name} panicked")]
+ ThreadPanicked {
+ /// The name of the thread.
+ name: String,
+ /// The panic message extracted from the panic payload.
+ message: Option<String>,
+ },
+}
+
/// A handle to send data to the worker thread (implements clone)
pub struct SendHandle<I> {
input: Sender<I>,
@@ -16,7 +32,7 @@ pub struct SendHandle<I> {
fn check_abort(abort: &Mutex<Option<String>>) -> Result<(), Error> {
let guard = abort.lock().unwrap();
if let Some(err_msg) = &*guard {
- return Err(format_err!("{}", err_msg));
+ return Err(Error::HandlerFailed(err_msg.clone()));
}
Ok(())
}
@@ -25,10 +41,7 @@ impl<I: Send> SendHandle<I> {
/// Send data to the worker threads
pub fn send(&self, input: I) -> Result<(), Error> {
check_abort(&self.abort)?;
- match self.input.send(input) {
- Ok(()) => Ok(()),
- Err(_) => bail!("send failed - channel closed"),
- }
+ self.input.send(input).map_err(|_| Error::ChannelClosed)
}
}
@@ -42,7 +55,6 @@ impl<I: Send> SendHandle<I> {
/// outstanding errors.
pub struct ParallelHandler<I> {
handles: Vec<JoinHandle<()>>,
- name: String,
input: Option<SendHandle<I>>,
}
@@ -60,7 +72,7 @@ impl<I: Send + 'static> ParallelHandler<I> {
/// with 'handler_fn'.
pub fn new<F>(name: &str, threads: usize, handler_fn: F) -> Self
where
- F: Fn(I) -> Result<(), Error> + Send + Clone + 'static,
+ F: Fn(I) -> Result<(), anyhow::Error> + Send + Clone + 'static,
{
let mut handles = Vec::new();
let (input_tx, input_rx) = bounded::<I>(threads);
@@ -83,7 +95,7 @@ impl<I: Send + 'static> ParallelHandler<I> {
if let Err(err) = (handler_fn)(data) {
let mut guard = abort.lock().unwrap();
if guard.is_none() {
- *guard = Some(err.to_string());
+ *guard = Some(format!("{err:#}"));
}
}
})
@@ -92,7 +104,6 @@ impl<I: Send + 'static> ParallelHandler<I> {
}
Self {
handles,
- name: name.to_string(),
input: Some(SendHandle {
input: input_tx,
abort,
@@ -118,32 +129,44 @@ impl<I: Send + 'static> ParallelHandler<I> {
check_abort(&abort)?;
drop(input);
- let msg_list = self.join_threads();
+ let mut msg_list = self.join_threads();
// an error might be encountered while waiting for the join
check_abort(&abort)?;
- if msg_list.is_empty() {
- return Ok(());
+ if let Some(e) = msg_list.pop() {
+ // Any error here is due to a thread panicking - let's just report that
+ // last panic that occurred.
+ Err(e)
+ } else {
+ Ok(())
}
- Err(format_err!("{}", msg_list.join("\n")))
}
- fn join_threads(&mut self) -> Vec<String> {
+ fn join_threads(&mut self) -> Vec<Error> {
let mut msg_list = Vec::new();
- let mut i = 0;
while let Some(handle) = self.handles.pop() {
+ let thread_name = handle.thread().name().unwrap_or("<unknown>").to_string();
+
if let Err(panic) = handle.join() {
- if let Some(panic_msg) = panic.downcast_ref::<&str>() {
- msg_list.push(format!("thread {} ({i}) panicked: {panic_msg}", self.name));
- } else if let Some(panic_msg) = panic.downcast_ref::<String>() {
- msg_list.push(format!("thread {} ({i}) panicked: {panic_msg}", self.name));
+ if let Some(message) = panic.downcast_ref::<&str>() {
+ msg_list.push(Error::ThreadPanicked {
+ name: thread_name,
+ message: Some(message.to_string()),
+ });
+ } else if let Some(message) = panic.downcast_ref::<String>() {
+ msg_list.push(Error::ThreadPanicked {
+ name: thread_name,
+ message: Some(message.to_string()),
+ });
} else {
- msg_list.push(format!("thread {} ({i}) panicked", self.name));
+ msg_list.push(Error::ThreadPanicked {
+ name: thread_name,
+ message: None,
+ });
}
}
- i += 1;
}
msg_list
}
--
2.47.3
next prev parent reply other threads:[~2026-03-12 13:53 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-12 13:52 [PATCH datacenter-manager/proxmox{,-backup,-yew-comp} 00/26] metric collection for the PDM host Lukas Wagner
2026-03-12 13:52 ` [PATCH proxmox 01/26] sys: procfs: don't read from sysfs during unit tests Lukas Wagner
2026-03-12 13:52 ` [PATCH proxmox 02/26] parallel-handler: import code from Proxmox Backup Server Lukas Wagner
2026-03-12 13:52 ` Lukas Wagner [this message]
2026-03-12 13:52 ` [PATCH proxmox 04/26] parallel-handler: add documentation Lukas Wagner
2026-03-12 13:52 ` [PATCH proxmox 05/26] parallel-handler: add simple unit-test suite Lukas Wagner
2026-03-12 13:52 ` [PATCH proxmox 06/26] disks: import from Proxmox Backup Server Lukas Wagner
2026-03-16 13:13 ` Arthur Bied-Charreton
2026-03-12 13:52 ` [PATCH proxmox 07/26] disks: fix typo in `initialize_gpt_disk` Lukas Wagner
2026-03-12 13:52 ` [PATCH proxmox 08/26] disks: add parts of gather_disk_stats from PBS Lukas Wagner
2026-03-12 13:52 ` [PATCH proxmox 09/26] disks: gate api macro behind 'api-types' feature Lukas Wagner
2026-03-12 13:52 ` [PATCH proxmox 10/26] disks: clippy: collapse if-let chains where possible Lukas Wagner
2026-03-12 13:52 ` [PATCH proxmox 11/26] procfs: add helpers for querying pressure stall information Lukas Wagner
2026-03-16 13:25 ` Arthur Bied-Charreton
2026-03-12 13:52 ` [PATCH proxmox 12/26] time: use u64 parse helper from nom Lukas Wagner
2026-03-12 13:52 ` [PATCH proxmox-backup 13/26] tools: move ParallelHandler to new proxmox-parallel-handler crate Lukas Wagner
2026-03-12 13:52 ` [PATCH proxmox-backup 14/26] tools: replace disks module with proxmox-disks Lukas Wagner
2026-03-16 13:27 ` Arthur Bied-Charreton
2026-03-12 13:52 ` [PATCH proxmox-backup 15/26] metric collection: use blockdev_stat_for_path from proxmox_disks Lukas Wagner
2026-03-12 13:52 ` [PATCH proxmox-yew-comp 16/26] node status panel: add `children` property Lukas Wagner
2026-03-12 13:52 ` [PATCH proxmox-yew-comp 17/26] RRDGrid: fix size observer by attaching node reference to rendered container Lukas Wagner
2026-03-12 13:52 ` [PATCH proxmox-yew-comp 18/26] RRDGrid: add padding and increase gap between elements Lukas Wagner
2026-03-12 13:52 ` [PATCH datacenter-manager 19/26] metric collection: clarify naming for remote metric collection Lukas Wagner
2026-03-12 13:52 ` [PATCH datacenter-manager 20/26] metric collection: fix minor typo in error message Lukas Wagner
2026-03-12 13:52 ` [PATCH datacenter-manager 21/26] metric collection: collect PDM host metrics in a new collection task Lukas Wagner
2026-03-12 13:52 ` [PATCH datacenter-manager 22/26] api: fix /nodes/localhost/rrddata endpoint Lukas Wagner
2026-03-12 13:52 ` [PATCH datacenter-manager 23/26] pdm: node rrd data: rename 'total-time' to 'metric-collection-total-time' Lukas Wagner
2026-03-12 13:52 ` [PATCH datacenter-manager 24/26] pdm-api-types: add PDM host metric fields Lukas Wagner
2026-03-12 13:52 ` [PATCH datacenter-manager 25/26] ui: node status: add RRD graphs for PDM host metrics Lukas Wagner
2026-03-12 13:52 ` [PATCH datacenter-manager 26/26] ui: lxc/qemu/node: use RRD value render helpers Lukas Wagner
2026-03-16 13:42 ` [PATCH datacenter-manager/proxmox{,-backup,-yew-comp} 00/26] metric collection for the PDM host Arthur Bied-Charreton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260312135229.420729-4-l.wagner@proxmox.com \
--to=l.wagner@proxmox.com \
--cc=pdm-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox