Skip to content

Commit 4295231

Browse files
committed
feat(utilities): add utilities for propagating errors across async tasks
1 parent 7787e6e commit 4295231

File tree

6 files changed

+90
-2
lines changed

6 files changed

+90
-2
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ package = [
124124
"dep:dotenvy"
125125
]
126126

127-
async = [ "snarkvm-ledger/async", "snarkvm-synthesizer/async" ]
127+
async = [ "snarkvm-ledger?/async", "snarkvm-synthesizer?/async", "snarkvm-utilities?/async" ]
128128
cuda = [ "snarkvm-algorithms/cuda" ]
129129
history = [ "snarkvm-synthesizer/history" ]
130130
parameters_no_std_out = [ "snarkvm-parameters/no_std_out" ]
@@ -515,6 +515,10 @@ default-features = false
515515
[workspace.dependencies.smallvec]
516516
version = "1.14"
517517

518+
[workspace.dependencies.tokio]
519+
version = "1"
520+
default-features = false
521+
518522
[workspace.dependencies.tempfile]
519523
version = "3.15"
520524

ledger/narwhal/data/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ features = [ "preserve_order" ]
3939

4040
[dependencies.tokio]
4141
optional = true
42-
version = "1"
42+
workspace = true
4343
features = [ "rt" ]
4444

4545
[dev-dependencies.snarkvm-ledger-block]

utilities/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ workspace = true
4040
[dependencies.colored]
4141
workspace = true
4242

43+
[dependencies.tokio]
44+
workspace = true
45+
optional = true
46+
features = ["rt"]
47+
4348
[dependencies.num_cpus]
4449
version = "1"
4550

@@ -83,6 +88,7 @@ workspace = true
8388

8489
[features]
8590
default = [ "derive" ]
91+
async = [ "tokio" ]
8692
derive = [ "snarkvm-utilities-derives" ]
8793
dev-print = [ ]
8894
serial = [ "derive" ]

utilities/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,11 @@ pub use serialize::*;
5858
pub mod errors;
5959
pub use errors::*;
6060

61+
#[cfg(feature = "async")]
62+
/// Helpers to spawn async tasks.
63+
pub mod task;
64+
#[cfg(feature = "async")]
65+
pub use task::*;
66+
6167
/// Use old name for backward-compatibility.
6268
pub use errors::io_error as error;

utilities/src/task.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (c) 2019-2025 Provable Inc.
2+
// This file is part of the snarkVM library.
3+
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at:
7+
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
use std::{
17+
future::Future,
18+
pin::Pin,
19+
task::{Context, Poll},
20+
};
21+
22+
/// Wrapper around `tokio::JoinHandle` that propagates panics.
23+
pub struct JoinHandle<R: Send + 'static> {
24+
inner: tokio::task::JoinHandle<R>,
25+
}
26+
27+
/// Wrapper around `tokio::spawn_blocking` that propagates panics.
28+
pub fn spawn_blocking<F, R>(f: F) -> JoinHandle<R>
29+
where
30+
F: FnOnce() -> R + Send + 'static,
31+
R: Send + 'static,
32+
{
33+
JoinHandle { inner: tokio::task::spawn_blocking(f) }
34+
}
35+
36+
/// Wrapper around `tokio::spawn` that propagates panics.
37+
pub fn spawn<F>(f: F) -> JoinHandle<F::Output>
38+
where
39+
F: Future + Send + 'static,
40+
F::Output: Send + 'static,
41+
{
42+
JoinHandle { inner: tokio::task::spawn(f) }
43+
}
44+
45+
impl<R: Send + 'static> JoinHandle<R> {
46+
pub fn abort(&self) {
47+
self.inner.abort();
48+
}
49+
}
50+
51+
impl<R: Send + 'static> Future for JoinHandle<R> {
52+
type Output = R;
53+
54+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
55+
let Poll::Ready(result) = std::pin::pin!(&mut self.inner).poll(cx) else {
56+
return Poll::Pending;
57+
};
58+
59+
match result {
60+
Ok(value) => Poll::Ready(value),
61+
Err(err) => {
62+
if err.is_panic() {
63+
// Resume the panic on the main task
64+
std::panic::resume_unwind(err.into_panic());
65+
} else {
66+
panic!("Got unexpected tokio error: {err}");
67+
}
68+
}
69+
}
70+
}
71+
}

0 commit comments

Comments
 (0)