Skip to content
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

Cannot async within traits #85

Open
NuSkooler opened this issue Nov 17, 2023 · 4 comments
Open

Cannot async within traits #85

NuSkooler opened this issue Nov 17, 2023 · 4 comments

Comments

@NuSkooler
Copy link

NuSkooler commented Nov 17, 2023

I'm able to use async_query() in simple tests, but not within an async trait. A simple example:

#[async_trait]
trait TestWmiTrait {
    async fn do_query() -> Result<()>;
}

struct TestWmi;
#[async_trait]
impl TestWmiTrait for TestWmi {
    async fn do_query() -> Result<()> {
        let com_con = COMLibrary::new()?;
        let wmi_con = WMIConnection::new(com_con.into())?;
        let _: Vec<UserProfile> = wmi_con.async_query().await?;
        Ok(())
    }
}

#[tokio::test]
async fn can_query_wmi_async() -> Result<()> {
    TestWmi::do_query().await?;
    Ok(())
}

Results in the following:

error: future cannot be sent between threads safely
   --> crates\bds_host\src\account\windows.rs:412:43
    |
412 |           async fn do_query() -> Result<()> {
    |  ___________________________________________^
413 | |             let com_con = COMLibrary::new()?;
414 | |             let wmi_con = WMIConnection::new(com_con.into())?;
415 | |             let _: Vec<UserProfile> = wmi_con.async_query().await?;
416 | |             Ok(())
417 | |         }
    | |_________^ future created by async block is not `Send`
    |
    = help: within `[async block@crates\bds_host\src\account\windows.rs:412:43: 417:10]`, the trait `Send` is not implemented for `*mut ()`
note: future is not `Send` as this value is used across an await
   --> crates\bds_host\src\account\windows.rs:415:61
    |
413 |             let com_con = COMLibrary::new()?;
    |                 ------- has type `wmi::COMLibrary` which is not `Send`
414 |             let wmi_con = WMIConnection::new(com_con.into())?;
415 |             let _: Vec<UserProfile> = wmi_con.async_query().await?;
    |                                                             ^^^^^ await occurs here, with `com_con` maybe used later
416 |             Ok(())
417 |         }
    |         - `com_con` is later dropped here
    = note: required for the cast from `Pin<Box<[async block@crates\bds_host\src\account\windows.rs:412:43: 417:10]>>` to `Pin<Box<(dyn Future<Output = std::result::Result<(), anyhow::Error>> + Send + 'async_trait)>>

Any ideas? Note that the same code works outside of a trait method.

@ohadravid
Copy link
Owner

Hi @NuSkooler 👋

That's because WMI needs to be initialized per-thread, so any future that uses the connection cannot move between threads (aka, the resulting futures are !Send).

async_trait supports this, so using #[async_trait(?Send)] should fix this.

Let me know if this helps!

@NuSkooler
Copy link
Author

NuSkooler commented Nov 20, 2023

@ohadravid Thanks, that makes sense. This does leave me in a dilemma, though it's likely my being fairly new to Rust: Removing Send trickles throughout the code meaning I can from my understanding, no longer use this method in other async/tokio code.

Is there a work around?

  • I have a struct with an async trait
  • From a trait method on the struct, on Windows, I need to query WMI
  • The trait method is queried from other Tokio tasks elsewhere

The work around I'm using right now is hoisting the work to non-async code that's wrapped with Tokio spawn_blocking, which doesn't feel that great.

@ohadravid
Copy link
Owner

Maybe something like #55 (comment) can help in your case?

@NuSkooler
Copy link
Author

@ohadravid That looks great, I'll check it out. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants