本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
注意
Rust 執行期用戶端
Lambda 函數處理常式是您的函數程式碼中處理事件的方法。當有人呼叫您的函數時,Lambda 會執行處理常式方法。函數會執行,直到處理常式傳回回應、結束或逾時為止。
此頁面說明如何在 Rust 中使用 Lambda 函數處理常式,包括專案初始化、命名慣例和最佳實務。此頁面也包含 Rust Lambda 函數的範例,該函數會取得訂單的相關資訊、產生文字檔案接收,並將此檔案放入 Amazon Simple Storage Service (S3) 儲存貯體。如需如何在撰寫函數後部署函數的詳細資訊,請參閱 使用 .zip 封存檔部署 Rust Lambda 函數。
主題
設定 Rust 處理常式專案
在 Rust 中使用 Lambda 函數時,程序涉及編寫程式碼、編譯程式碼,以及將編譯的成品部署至 Lambda。在 Rust 中設定 Lambda 處理常式專案的最簡單方法是使用 AWS Lambda Runtime for Rustlambda_runtime
)。
使用下列命令來安裝 Rust 的 AWS Lambda 執行期:
cargo install cargo-lambda
成功安裝 後cargo-lambda
,請使用下列命令來初始化新的 Rust Lambda 函數處理常式專案:
cargo lambda new example-rust
當您執行此命令時,命令列界面 (CLI) 會詢問幾個有關 Lambda 函數的問題:
-
HTTP 函數 – 如果您想要透過 API Gateway 或函數 URL 叫用函數,請回答是。否則,請回答否。 在此頁面上的範例程式碼中,我們使用自訂 JSON 事件調用函數,因此我們回答否。
-
事件類型 – 如果您想要使用預先定義的事件形狀來叫用函數,請選取正確的預期事件類型。否則,請將此選項保留空白。在此頁面上的範例程式碼中,我們使用自訂 JSON 事件調用函數,因此將此選項保留空白。
命令成功執行後,請輸入專案的主目錄:
cd example-rust
此命令會在 src
目錄中產生 generic_handler.rs
檔案和 main.rs
檔案。generic_handler.rs
可用來自訂一般事件處理常式。main.rs
檔案包含您的主要應用程式邏輯。Cargo.toml
檔案包含套件的中繼資料,並列出其外部相依性。
Rust Lambda 函數程式碼範例
下列範例 Rust Lambda 函數程式碼會取得訂單的相關資訊、產生文字檔案接收,並將此檔案放入 Amazon S3 儲存貯體。
範例 main.rs
Lambda 函數
use aws_sdk_s3::{Client, primitives::ByteStream};
use lambda_runtime::{run, service_fn, Error, LambdaEvent};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::env;
#[derive(Deserialize, Serialize)]
struct Order {
order_id: String,
amount: f64,
item: String,
}
async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error> {
let payload = event.payload;
// Deserialize the incoming event into Order struct
let order: Order = serde_json::from_value(payload)?;
let bucket_name = env::var("RECEIPT_BUCKET")
.map_err(|_| "RECEIPT_BUCKET environment variable is not set")?;
let receipt_content = format!(
"OrderID: {}\nAmount: ${:.2}\nItem: {}",
order.order_id, order.amount, order.item
);
let key = format!("receipts/{}.txt", order.order_id);
let config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
let s3_client = Client::new(&config);
upload_receipt_to_s3(&s3_client, &bucket_name, &key, &receipt_content).await?;
Ok("Success".to_string())
}
async fn upload_receipt_to_s3(
client: &Client,
bucket_name: &str,
key: &str,
content: &str,
) -> Result<(), Error> {
client
.put_object()
.bucket(bucket_name)
.key(key)
.body(ByteStream::from(content.as_bytes().to_vec())) // Fixed conversion
.content_type("text/plain")
.send()
.await?;
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Error> {
run(service_fn(function_handler)).await
}
此 main.rs
檔案包含以下程式碼區段:
-
use
陳述式:使用這些命令來匯入 Lambda 函數所需的 Rust 木箱和方法。 -
#[derive(Deserialize, Serialize)]
:定義此 Rust 結構中預期輸入事件的形狀。 -
async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error>
:這是主要處理常式方法,其中包含應用程式的主要邏輯。 -
async fn upload_receipt_to_s3 (...)
:這是主要方法所參考的協助程式function_handler
方法。 -
#[tokio::main]
:這是標記 Rust 程式進入點的巨集。它也會設定 Tokio 執行時間,讓您的 main()
方法能夠使用async
/await
並以非同步方式執行。 -
async fn main() -> Result<(), Error>
:main()
函數是程式碼的進入點。其中,我們將 指定function_handler
為主要處理常式方法。
下列Cargo.toml
檔案隨附此函數。
[package]
name = "example-rust"
version = "0.1.0"
edition = "2024"
[dependencies]
aws-config = "1.5.18"
aws-sdk-s3 = "1.78.0"
lambda_runtime = "0.13.0"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
若要讓此函數正常運作,其執行角色必須允許 s3:PutObject
動作。此外,請確保定義 RECEIPT_BUCKET
環境變數。成功調用後,Amazon S3 儲存貯體應包含收據檔案。
Rust 處理常式的有效類別定義
在大多數情況下,您在 Rust 中定義的 Lambda 處理常式簽章會有下列格式:
async fn function_handler(event: LambdaEvent<T>) -> Result<U, Error>
對於此處理常式:
-
此處理常式的名稱為
function_handler
。 -
處理常式的單一輸入是 事件,類型為
LambdaEvent<T>
。-
LambdaEvent
是來自lambda_runtime
木箱的包裝函式。使用此包裝函式可讓您存取內容物件,其中包含 Lambda 特定的中繼資料,例如呼叫的請求 ID。 -
T
是還原序列化事件類型。例如,這可以是serde_json::Value
,允許處理常式擷取任何一般 JSON 輸入。或者,ApiGatewayProxyRequest
如果您的函數預期特定的預先定義輸入類型,這可以是類似 的類型。
-
-
處理常式的傳回類型為
Result<U, Error>
。-
U
是還原序列化的輸出類型。U
必須實作serde::Serialize
訓練,Lambda 才能將傳回值轉換為 JSON。例如,只要實作String
,U
可以是簡單的類型,例如serde_json::Value
、 或自訂結構Serialize
。當您的程式碼到達 Ok(U) 陳述式時,這表示成功執行,而您的函數會傳回類型 的值U
。 -
當您的程式碼發生錯誤 (即
Err(Error)
) 時,您的函數會在 Amazon CloudWatch 中記錄錯誤,並傳回 類型的錯誤回應Error
。
-
在我們的範例中,處理常式簽章如下所示:
async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error>
其他有效的處理常式簽章可以具有下列功能:
-
省略
LambdaEvent
包裝函式 – 如果您省略LambdaEvent
,則會失去函數中 Lambda 內容物件的存取權。以下是這類簽章的範例:async fn handler(event: serde_json::Value) -> Result<String, Error>
-
使用單位類型做為輸入 – 對於 Rust,您可以使用單位類型來代表空白輸入。這通常用於具有定期排程調用的函數。以下是這類簽章的範例:
async fn handler(): ()) -> Result<Value, Error>
處理常式命名慣例
Rust 中的 Lambda 處理常式沒有嚴格的命名限制。雖然您可以為處理常式使用任何名稱,但 Rust 中的函數名稱通常位於 中snake_case
。
對於較小的應用程式,例如在此範例中,您可以使用單一main.rs
檔案來包含所有程式碼。對於較大的專案, main.rs
應該包含函數的進入點,但您可以為 設定其他檔案,將程式碼分隔為邏輯模組。例如,您可能具有下列檔案結構:
/example-rust
│── src/
│ ├── main.rs # Entry point
│ ├── handler.rs # Contains main handler
│ ├── services.rs # [Optional] Back-end service calls
│ ├── models.rs # [Optional] Data models
│── Cargo.toml
定義和存取輸入事件物件
JSON 是 Lambda 函數最常見的標準輸入格式。在此範例中,函數預期輸入類似以下內容:
{
"order_id": "12345",
"amount": 199.99,
"item": "Wireless Headphones"
}
在 Rust 中,您可以在結構中定義預期輸入事件的形狀。在此範例中,我們定義下列結構來代表 Order
:
#[derive(Deserialize, Serialize)]
struct Order {
order_id: String,
amount: f64,
item: String,
}
此 struct 符合預期的輸入形狀。在此範例中,#[derive(Deserialize, Serialize)]
巨集會自動產生用於序列化和還原序列化的程式碼。這表示我們可以使用 serde_json::from_value()
方法將一般輸入 JSON 類型還原序列化到結構中。這在處理常式的前幾行中得以曾現:
async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error> {
let payload = event.payload;
// Deserialize the incoming event into Order struct
let order: Order = serde_json::from_value(payload)?;
...
}
然後,您可以存取物件的欄位。例如,使用 order_id
可以從原始輸入擷取 order.order_id
的值。
預先定義的輸入事件類型
aws_lambda_events
木箱中有許多預先定義的輸入事件類型。例如,如果您想要使用 API Gateway 叫用函數,包括下列匯入:
use aws_lambda_events::event::apigw::ApiGatewayProxyRequest;
然後,請確定您的主要處理常式使用以下簽章:
async fn handler(event: LambdaEvent<ApiGatewayProxyRequest>) -> Result<String, Error> {
let body = event.payload.body.unwrap_or_default();
...
}
如需其他預先定義輸入事件類型的詳細資訊,請參閱 aws_lambda_events 木箱
存取和使用 Lambda 內容物件
Lambda 內容物件 包含有關調用、函數以及執行環境的資訊。在 Rust 中,LambdaEvent
包裝函式包含內容物件。例如,您可以使用內容物件,以下列程式碼擷取目前調用的要求 ID:
async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error> {
let request_id = event.context.request_id;
...
}
如需內容物件的詳細資訊,請參閱使用 Lambda 內容物件擷取 Rust 函數資訊。
在處理常 適用於 Rust 的 AWS SDK 式中使用
通常,您將使用 Lambda 函數與其他 AWS 資源互動或進行更新。連接這些資源的最簡單方法是使用 適用於 Rust 的 AWS SDK。
若要將 SDK 相依性新增至函數,請在您的 Cargo.toml
檔案中新增它們。建議您只新增函數所需的程式庫。在先前的範例程式碼中,我們使用 aws_sdk_s3::Client
。在 Cargo.toml
檔案中,您可以透過在 [dependencies]
區段下新增以下行來新增此相依性:
aws-sdk-s3 = "1.78.0"
注意
這可能不是最新版本。為您的應用程式選擇適當的版本。
,直接在您的程式碼中匯入相依性:
use aws_sdk_s3::{Client, primitives::ByteStream};
然後,範例程式碼會初始化 Amazon S3 用戶端,如下所示:
let config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
let s3_client = Client::new(&config);
初始化 SDK 用戶端之後,您就可以使用它來與其他 AWS 服務互動。範例程式碼會在upload_receipt_to_s3
協助程式函數中呼叫 Amazon S3 PutObject
API。
存取環境變數
在處理常式程式碼中,您可以使用 env::var
方法參考任何環境變數。在此範例中,我們使用以下程式碼來參考定義的 RECEIPT_BUCKET
環境變數:
let bucket_name = env::var("RECEIPT_BUCKET")
.map_err(|_| "RECEIPT_BUCKET environment variable is not set")?;
使用共用狀態
您可以宣告獨立於 Lambda 函數處理常式程式碼的共用變數。這些變數可協助您在函數接收任何事件之前在 初始化階段 過程中載入狀態資訊。例如,您可以透過更新main
函數和處理常式簽章,修改此頁面上的程式碼,以在初始化 Amazon S3 用戶端時使用共用狀態:
async fn function_handler(client: &Client, event: LambdaEvent<Value>) -> Result<String, Error> {
...
upload_receipt_to_s3(client, &bucket_name, &key, &receipt_content).await?;
...
}
...
#[tokio::main]
async fn main() -> Result<(), Error> {
let shared_config = aws_config::from_env().load().await;
let client = Client::new(&shared_config);
let shared_client = &client;
lambda_runtime::run(service_fn(move |event: LambdaEvent<Request>| async move {
handler(&shared_client, event).await
}))
.await
Rust Lambda 函數的程式碼最佳實務
請遵循下列清單中的準則,在建置 Lambda 函數時使用最佳編碼實務:
-
區隔 Lambda 處理常式與您的核心邏輯。能允許您製作更多可測單位的函式。
-
最小化依存項目的複雜性。偏好更簡易的框架,其可快速在執行環境啟動時載入。
-
將部署套件最小化至執行時間所必要的套件大小。這能減少您的部署套件被下載與呼叫前解壓縮的時間。
-
請利用執行環境重新使用來改看函式的效能。在函式處理常式之外初始化 SDK 用戶端和資料庫連線,並在本機快取
/tmp
目錄中的靜態資產。由您函式的相同執行個體處理的後續叫用可以重複使用這些資源。這可藉由減少函數執行時間來節省成本。若要避免叫用間洩漏潛在資料,請不要使用執行環境來儲存使用者資料、事件,或其他牽涉安全性的資訊。如果您的函式依賴無法存放在處理常式內記憶體中的可變狀態,請考慮為每個使用者建立個別函式或個別函式版本。
-
使用 Keep-Alive 指令維持持續連線的狀態。Lambda 會隨著時間的推移清除閒置連線。叫用函數時嘗試重複使用閒置連線將導致連線錯誤。若要維護持續連線,請使用與執行階段相關聯的 keep-alive (保持啟用) 指令。如需範例,請參閱在 Node.js 中重複使用 Keep-Alive 的連線。
-
使用環境變數將操作參數傳遞給您的函數。例如,如果您正在寫入到 Amazon S3 儲存貯體,而非對您正在寫入的儲存貯體名稱進行硬式編碼,請將儲存貯體名稱設定為環境變數。
-
避免在 Lambda 函數中使用遞迴調用,其中函數會調用自己或啟動可能再次調用函數的程序。這會導致意外的函式呼叫量與升高的成本。若您看到意外的調用數量,當更新程式碼時,請立刻將函數的預留並行設為
0
,以調節對函數的所有調用。 -
請勿在您的 Lambda 函數程式碼中使用未記錄的非公有 API。對於 AWS Lambda 受管執行期,Lambda 會定期將安全性和功能更新套用至 Lambda 的內部 APIs。這些內部 API 更新可能是向後不相容的,這會導致意外結果,例如若您的函數依賴於這些非公有 API,則叫用失敗。請參閱 API 參考查看公開可用 API 的清單。
-
撰寫等冪程式碼。為函數撰寫等冪程式碼可確保採用相同方式來處理重複事件。程式碼應正確驗證事件並正常處理重複的事件。如需詳細資訊,請參閱 How do I make my Lambda function idempotent?
(如何讓 Lambda 函數等冪?)。