Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Migrating from rocket 0.4 to rocket 0.5 with sync_db_pools: How to return the query results sync?

I am trying to migrate an application from rocket 0.4 to rocket 0.5 Before it was using rocket_contrib feature diesel_postgres_pool and I though rocket_sync_db_pools would be the best fit for migration (but I am open to alternatives here)

I tried to change the code like this:

-        let quality = subjects::table
-            .find(&sub)
-            .select(subjects::quality)
-            .first::<i16>(&conn.0)
-            .ok();
+        let quality = conn.run( move |conn| {
+            subjects::table
+                .find(&sub)
+                .select(subjects::quality)
+                .first::<i16>(conn)
+                .ok();
+        });

But now I am not getting the actual result but a Promise.

The documentation suggests to use .await which seems to cause that the calling func needs to be async, too. But I cannot do this, because the code is also used in traits, which cannot be async easily.

I am pretty new to rust and don't understand two (or more) things:

  1. Why does my function have to be async if we are waiting for the result (with await)?
  2. Why does the sync DB pool return async promises / need async functions.

Is this the right approach?

What are the alternatives to fix this without rebuilding the full application?

EDIT

This is a step forward, after importing async_trait.


#[async_trait]
impl Statistic for Subject {
    async fn compute(conn: &DbConn, sub: String) -> Result<Self, Error> {


[...]

        let quality = conn.run( move |conn| {
            return subjects::table
                .find(&sub)
                .select(subjects::quality)
                .first::<i16>(conn)
                .ok();
        }).await;

But it seems to bring problems on the callee of compute:

        identifiers
            .map(|identifier| {
                Self::compute(&conn, identifier.clone()).map(|statistic| (identifier, statistic))
            })
            .collect()

Causes an error:

23  |                 Self::compute(&conn, identifier.clone()).map(|statistic| (identifier, statistic))
    |                                                          ^^^ `Pin<Box<dyn std::future::Future<Output = Result<Self, error::Error>> + std::marker::Send>>` is not an iterator

EDIT2: I might not need the async_trait crate, as rocket already supplies such a solution: https://rocket.rs/master/guide/upgrading-from-0.4/#async-traits

EDIT3: So I tried:

        identifiers
            .map(async move |identifier| {
                join_all(Self::compute(&conn, identifier.clone())).await.map(|statistic| (identifier, statistic))
            })
            .collect()

This leads to a new error :-)

error[E0658]: async closures are unstable
  --> src/aggregator.rs:23:18
   |
23 |             .map(async move |identifier| {
   |                  ^^^^^
   |
   = note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
   = help: to use an async block, remove the `||`: `async {`

EDIT4:

After trying pigeonhands answer with this code:

        let quality = Handle::current().block_on(async move {
            conn.run(move |conn| {
                subjects::table
                    .find(&sub)
                    .select(subjects::quality)
                    .first::<i16>(conn)
                    .ok();
            })
        });
        Ok(Subject {
            sub,
            quality,
            count,
            opinion_count,
            positive_count,
            confirmed_count,
        })

I am getting

error[E0308]: mismatched types
  --> src/aggregator.rs:84:13
   |
74 |             conn.run(move |conn| {
   |                      ----------- the found closure
...
84 |             quality,
   |             ^^^^^^^ expected enum `std::option::Option`, found opaque type
like image 826
Alex Avatar asked Dec 06 '25 20:12

Alex


1 Answers

You could use tokio's block_on to resolve the future in a non-async function

let quality = Handle::current().block_on(async move {
    conn.run( move |conn| {
        subjects::table
            .find(&sub)
            .select(subjects::quality)
            .first::<i16>(conn)
            .ok()
    }).await
});.

Or you could use the diesel crate directly with the r2d2 feature for pooling, witch does not require using await. (this is what crates.io does with axum)

like image 151
pigeonhands Avatar answered Dec 08 '25 22:12

pigeonhands



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!