首页 > 解决方案 > 包装一个异步函数

问题描述

rust 的 AWS Lambda 运行时要求处理程序类似于async fn handler(event: Value, cx: Context) -> Result<Value, Error>. 它处理您在内部返回的错误,但我不喜欢它如何记录它们。我想创建一个函数,我可以传递一个处理函数,它返回一个包装版本,它只调用原始版本,检查它的结果,也许是日志,然后返回结果。事实证明,这……很困难。

我已经设法用宏来做到这一点,但我不知道如何让一个真正的功能来做到这一点。任何帮助将非常感激。代码:

use anyhow::{Result};
use lambda_runtime::{handler_fn, Context, Error};
use serde_json::{Value};

// handler
async fn handler(event: Value, cx: Context) -> Result<Value> {
  Ok(())
}

// non-generic version (works)
async fn wrapper(event: Value, cx: Context) -> Result<Value> {
    let res = handler(event, cx).await;

    if let Err(e) = &res {
        log::error!("got error from handler: {:?}", &e);
    }
    res
}

// macro (works)
macro_rules! wrap_handler {
    ($f:ident) => {{
        |e: Value, c: Context| async {
            let res = $f(e, c).await;
            if let Err(e) = &res {
                log::error!("got error from handler: {:?}", &e);
            }
            res
        }
    }};
}

// attempt at generic wrapper-creator fn
// should take the function to wrap, and return a Fn wrapping it
use std::future::Future;
use std::pin::Pin;
pub fn make_wrapper<F, FO>(
    f: F,
) -> Box<dyn Fn(Value, Context) -> Pin<Box<dyn Future<Output = Result<Value>> + 'static>> + 'static>
where
    F: Fn(Value, Context) -> FO + 'static,
    FO: Future<Output = Result<Value>> + 'static,
{
    use std::sync::Arc;
    let af = Arc::new(f);
    Box::new(move |v: Value, c: Context| {
        let my_f = af.clone();
        Box::pin(async move {
            //
            my_f(v, c).await
        })
    })
}

// main
#[tokio::main]
async fn main() -> Result<(), Error> {
    // use the non-generic version
    let func = handler_fn(wrapper);
    // OR
    // use the macro
    let func = handler_fn(wrap_handler!(handler));
    // OR
    // use the generic wrapper function
    let func = handler_fn(make_wrapper(handler));

    lambda_runtime::run(func).await?;
    Ok(())
}


我最近尝试的错误(上面代码中的 fn )是:

error[E0277]: `dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>` cannot be sent between threads safely
   --> src/bin/classify-partition.rs:126:25
    |
126 |     lambda_runtime::run(func).await?;
    |                         ^^^^ `dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>` cannot be sent between threads safely
    |
   ::: /home/miles/.cargo/registry/src/github.com-1ecc6299db9ec823/lambda_runtime-0.3.0/src/lib.rs:294:24
    |
294 |     F: Handler<A, B> + Send + Sync + 'static,
    |                        ---- required by this bound in `run`
    |
    = help: the trait `Send` is not implemented for `dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>`
    = note: required because of the requirements on the impl of `Send` for `Unique<dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>>`
    = note: required because it appears within the type `Box<dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>>`
    = note: required because it appears within the type `HandlerFn<Box<dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>>>`

error[E0277]: `dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>` cannot be shared between threads safely
   --> src/bin/classify-partition.rs:126:25
    |
126 |     lambda_runtime::run(func).await?;
    |                         ^^^^ `dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>` cannot be shared between threads safely
    |
   ::: /home/miles/.cargo/registry/src/github.com-1ecc6299db9ec823/lambda_runtime-0.3.0/src/lib.rs:294:31
    |
294 |     F: Handler<A, B> + Send + Sync + 'static,
    |                               ---- required by this bound in `run`
    |
    = help: the trait `Sync` is not implemented for `dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>`
    = note: required because of the requirements on the impl of `Sync` for `Unique<dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>>`
    = note: required because it appears within the type `Box<dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>>`
    = note: required because it appears within the type `HandlerFn<Box<dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>>>`

error[E0277]: `(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)` cannot be sent between threads safely
   --> src/bin/classify-partition.rs:126:25
    |
126 |     lambda_runtime::run(func).await?;
    |                         ^^^^ `(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)` cannot be sent between threads safely
    |
    = help: the trait `Send` is not implemented for `(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)`
    = note: required because of the requirements on the impl of `Send` for `Unique<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>`
    = note: required because it appears within the type `Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>`
    = note: required because it appears within the type `Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>`
    = note: required because of the requirements on the impl of `Handler<Value, Value>` for `HandlerFn<Box<dyn Fn(Value, lambda_runtime::Context) -> Pin<Box<(dyn Future<Output = Result<Value, anyhow::Error>> + 'static)>>>>`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0277`.
error: could not compile `enrichment-service-functions`

To learn more, run the command again with --verbose.

标签: rustaws-lambda

解决方案


推荐阅读