-
Notifications
You must be signed in to change notification settings - Fork 43
[illumos-utils] Use tokio::process::Command, not std::process::Command #8141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
sled-diagnostics/src/logs.rs
Outdated
"error" => ?e, | ||
); | ||
let DiagnosticsSnapshot { log, snapshot, .. } = self; | ||
tokio::task::spawn({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To confirm: is it critical that the snapshot blocks the drop method? Async drop does not exist in rust.
This API, as implemented, creates the background task but does not await for it to complete.
@@ -6,12 +6,13 @@ | |||
|
|||
use crate::link::{Link, LinkKind}; | |||
use crate::zone::IPADM; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes in this file - and others within illumos-utils/src/...
- are representative of "what actually is changing in this PR":
- std::process::Command -> tokio::process::Command
- This makes the function async
- The rest of the changes are fall-out from this, identifying blocks of code as asynchronous
sled-diagnostics/src/logs.rs
Outdated
// Free all of the log_snapshots | ||
drop(log_snapshots); | ||
|
||
let snapshots = get_sled_diagnostics_snapshots(zfs_filesystem); | ||
let snapshots = | ||
get_sled_diagnostics_snapshots(zfs_filesystem).await; | ||
assert!(snapshots.is_empty(), "no snapshots left behind"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's critical that the drop method is synchronous however it does introduce a race condition in the test here, we may be able to work around it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed the behavior here to use a more explicit drop, and log errors if this wasn't handled. I also tried to refactor above to make this case less likely -- cleaning up snapshots at a higher-level in the call to get_zone_logs
@@ -175,6 +176,7 @@ pub struct Dladm(()); | |||
/// Describes the API for interfacing with Data links. | |||
/// | |||
/// This is a trait so that it can be faked out for tests. | |||
#[async_trait::async_trait] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine, but I'm curious (and maybe this is a "Friday afternoon Rust chat" question more than a PR question) - is there a reason to prefer async_trait
over returning impl Future<Output = ...> + Send
now that Rust supports that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is slightly more painful for default methods - I see elsewhere we have the pattern of:
trait Api {
fn foobar(&self) -> impl Future<Output=Baz> + Send;
}
impl Api for MyStruct {
async fn foobar(&self) -> Baz { ... }
}
But if I try to use a default impl of:
trait Api {
fn foobar(&self) -> impl Future<Output=Baz> + Send {
// Do anything async
}
}
I'll get the error the ".await" is only allowed in async blocks, and foobar
isn't an async block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be able to get away with
trait Api {
fn foobar(&self) -> impl Future<Output=Baz> + Send {
async {
// Do anything async
}
}
}
but that might also be kind of a pain if you're doing anything with self
. Anyway - it's a good point; async_trait
does seem to be smoother still, at least for this case.
illumos-utils/src/zone.rs
Outdated
zone: Option<&'a str>, | ||
addrobj: &AddrObject, | ||
addrtype: AddressRequest, | ||
) -> Result<IpNetwork, EnsureAddressError> { | ||
|zone, addrobj, addrtype| -> Result<IpNetwork, anyhow::Error> { | ||
match Self::get_address_impl(zone, addrobj) { | ||
#[allow(clippy::redundant_closure_call)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this redundant closure? (If so maybe worth a short comment explaining why)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll avoid it by pulling this out to a new method instead. We're using it to make translation of the error type more convenient.
sled-diagnostics/src/logs.rs
Outdated
|
||
async fn destroy(&mut self) -> Result<(), LogError> { | ||
if !self.destroyed { | ||
self.destroyed = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be set after Zfs::destroy_snapshot()
returns Ok(_)
? (As written the caller couldn't retry destruction, although maybe that doesn't matter at the moment.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I'll move it down. I don't think we're trying to call this again from any pub
codepaths, but I don't see a problem with making it retryable either.
Many commands in
illumos-utils
bottomed out in a call to "std::process::Command", eventuallyexec-ing a process. These commands were often used from asynchronous code, even though they
could block the calling thread.
This PR converts many - but not all - of these calls to use
tokio::process::Command
instead, whichno longer blocks the calling thread.