我正在尝试使用 Cargo-lambda 在 Rust 中为 AWS 编写一个 lambda 函数。当我调用
cargo lambda new
时,由 cargo lambda build --release --arm64
生成的示例函数构建得很好。但是,当我尝试构建代码时,我按照 https://github.com/awslabs/aws-lambda-rust-runtime 和 https://www.cargo-lambda.info/ 上的说明和示例进行编写guide/getting-started.html,构建无法找到 OpenSSL 的标头。我已经使用 pacman -S openssl
安装了 OpenSSL,并运行了 pacman -S linux-headers
,并尝试运行 export OPENSSL_LIB_DIR=/usr/lib/
和 export OPENSSL_INCLUDE_DIR=/usr/include/openssl/
以及在我的 Fish 配置文件中设置它们,但都不起作用。我过不去:
cargo:warning=build/expando.c:1:10: fatal error: 'openssl/opensslv.h' file not found
cargo:warning=#include <openssl/opensslv.h>
我已经目视验证了该文件存在于目录中,但由于某种原因
openssl-sys-0.9.87
无法找到它并出现恐慌。有其他人遇到过这种情况,或者有人有任何我可以尝试的想法吗?我不确定问题是否出在我的 Cargo-lambda 设置、我的 OpenSSL 设置、我的代码或其他方面。
此代码是使用
cargo lambda new project_name
生成的并且构建良好:
use lambda_runtime::{run, service_fn, Error, LambdaEvent};
use serde::{Deserialize, Serialize};
/// Main function generated by cargo-lambda
#[tokio::main]
async fn main() -> Result<(), Error> {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
// disable printing the name of the module in every log line.
.with_target(false)
// disabling time is handy because CloudWatch will add the ingestion time.
.without_time()
.init();
lambda_runtime::run(service_fn(function_handler)).await
}
/// This is a made-up example.
#[derive(Deserialize)]
struct Request {
command: String,
}
/// This is a made-up example of what a response structure may look like.
#[derive(Serialize)]
struct Response {
req_id: String,
msg: String,
}
/// This is the main body for the function.
/// Write your code inside it.
async fn function_handler(event: LambdaEvent<Request>) -> Result<Response, Error> {
// Extract some useful info from the request
let command = event.payload.command;
// Prepare the response
let resp = Response {
req_id: event.context.request_id,
msg: format!("Command {}.", command),
};
// Return `Response` (it will be serialized to JSON automatically by the runtime)
Ok(resp)
}
这是我正在尝试构建的代码,但从
openssl-sys-0.9.87
中收到错误,即使它是在同一个项目中编写的并且遵循在线文档中的示例:
use lambda_runtime::{run, service_fn, Error, LambdaEvent};
use reqwest::blocking::Client;
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
#[tokio::main]
async fn main() -> Result<(), lambda_runtime::Error> {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
// disable printing the name of the module in every log line.
.with_target(false)
// disabling time is handy because CloudWatch will add the ingestion time.
.without_time()
.init();
let query = service_fn(query_handler);
run(query).await
}
async fn query_handler(event: LambdaEvent<Value>) -> Result<Value, Error> {
let (event, _context) = event.into_parts();
let symbol = event["symbol"].to_string();
let message = query_price(symbol)?;
Ok(json!({ "message": format!("{}", message) }))
}
#[derive(Deserialize, Debug)]
#[allow(non_snake_case)]
struct PriceQuote {
pub s: String,
pub symbol: Vec<String>,
pub ask: Vec<f32>,
pub askSize: Vec<u32>,
pub bid: Vec<f32>,
pub bidSize: Vec<u32>,
pub mid: Vec<f32>,
pub last: Vec<f32>,
pub volume: Vec<u32>,
pub updated: Vec<u32>,
}
fn query_price(symbol: String) -> Result<String, reqwest::Error> {
//let symbol = "AAPL";
let url = format!("https://api.marketdata.app/v1/stocks/quotes/{}", symbol);
let client = Client::new();
let response = client.get(url).send()?;
let price_quote: PriceQuote = response.json()?;
let symbol: &String = &price_quote.symbol[0];
let last_price: &f32 = &price_quote.last[0];
Ok(format!("Last price for {} is {}", symbol, last_price).to_string())
}
为什么一个会建造而另一个却不会?我添加的依赖项是否会扰乱它?我的 OpenSSL 版本是否错误?我做错了吗?我缺少什么?抱歉,如果这些都是愚蠢的问题,我是 AWS 新手,我的头在旋转。
不确定到底出了什么问题,但似乎 reqwest 板条箱是问题的根源。我从来没有遇到过这个问题,除了通过 Cargo-lambda 构建时,所以我想它与 Zig 有关?
无论哪种方式,都可以通过直接在 Cargo.toml 中添加 openssl 来解决:
openssl = { version = "0.10.35", features = ["vendored"] }
这似乎为 reqwest 提供了正确的链接,并允许构建 Cargo lambda。还没有测试 reqwest 是否仍然有效,但我认为没有理由不应该。
更新:该功能部署并且 reqwest 工作正常
AWS Lambda 函数在 Amazon Linux 2 沙箱内执行,其中仅包含运行 Rust 二进制文件的最低限度功能,不包含 OpenSSL。
cargo lambda build
不是针对主机(构建)系统上可用的内容进行构建,而是针对来宾(运行时)Linux 沙箱上可用的内容进行构建,因此无法找到 OpenSSL 标头。 Cargo Lambda 文档提及:
`*-sys` libraries are not guaranteed to work unless they are completely linked to your binary
Rust
openssl
crate 可以切换为与 openssl = { version = "0.10.35", features = ["vendored"] }
中的 Cargo.toml
进行静态编译和链接(如 j-stach 已经提到的)。类似地,Rust reqwest
crate(依赖于 OpenSSL 的 HTTPS 客户端)可以切换为使用 reqwest = { version = "0.11.23", features = ["native-tls-vendored"] }
或 reqwest = { version = "0.11.23", default-features = false, features = ["rustls"] }
进行静态编译和链接。
最后,如果你遇到心爱的
cargo lambda build
issue “不支持的链接器参数:--no-undefined-version”,只需使用 rustup default 1.69
将你的 Rust 降级到 1.69。