Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.
Anmerkung
Der Rust-Laufzeit-Client
Der Lambda-Funktionshandler ist die Methode in Ihrem Funktionscode, die Ereignisse verarbeitet. Wenn Ihre Funktion aufgerufen wird, führt Lambda die Handler-Methode aus. Ihre Funktion wird so lange ausgeführt, bis der Handler eine Antwort zurückgibt, beendet wird oder ein Timeout auftritt.
Auf dieser Seite wird beschrieben, wie Sie mit Lambda-Funktionshandlern in Rust arbeiten, einschließlich Projektinitialisierung, Benennungskonventionen und Best Practices. Diese Seite enthält auch ein Beispiel für eine Rust-Lambda-Funktion, die Informationen über eine Bestellung aufnimmt, eine Textdateiquittung erstellt und diese Datei in einen Amazon Simple Storage Service (S3) -Bucket legt. Weitere Informationen darüber, wie Sie Ihre Funktion nach dem Schreiben bereitstellen, finden Sie unterBereitstellen von Lambda-Rust-Funktionen mit ZIP-Dateiarchiven.
Richten Sie Ihr Rust-Handler-Projekt ein
Wenn Sie mit Lambda-Funktionen in Rust arbeiten, umfasst der Prozess das Schreiben Ihres Codes, das Kompilieren und das Bereitstellen der kompilierten Artefakte in Lambda. Der einfachste Weg, ein Lambda-Handler-Projekt in Rust einzurichten, ist die Verwendung der AWS Lambda Runtime for Rustlambda_runtime
), die das Schreiben von Lambda-Funktionen in Rust und die Anbindung an die Ausführungsumgebung AWS Lambda unterstützt.
Verwenden Sie den folgenden Befehl, um AWS Lambda Runtime for Rust zu installieren:
cargo install cargo-lambda
Verwenden Sie nach erfolgreicher Installation den folgenden Befehlcargo-lambda
, um ein neues Rust Lambda Function Handler-Projekt zu initialisieren:
cargo lambda new example-rust
Wenn Sie diesen Befehl ausführen, stellt Ihnen die Befehlszeilenschnittstelle (CLI) einige Fragen zu Ihrer Lambda-Funktion:
-
HTTP-Funktion — Wenn Sie beabsichtigen, Ihre Funktion über das API Gateway oder eine Funktions-URL aufzurufen, antworten Sie mit Ja. Andernfalls antworten Sie mit Nein. Im Beispielcode auf dieser Seite rufen wir unsere Funktion mit einem benutzerdefinierten JSON-Ereignis auf und antworten daher mit Nein.
-
Ereignistyp — Wenn Sie eine vordefinierte Ereignisform verwenden möchten, um Ihre Funktion aufzurufen, wählen Sie den richtigen erwarteten Ereignistyp aus. Andernfalls lassen Sie diese Option leer. Im Beispielcode auf dieser Seite rufen wir unsere Funktion mit einem benutzerdefinierten JSON-Ereignis auf, sodass wir diese Option leer lassen.
Nachdem der Befehl erfolgreich ausgeführt wurde, geben Sie das Hauptverzeichnis Ihres Projekts ein:
cd example-rust
Dieser Befehl generiert eine generic_handler.rs
Datei und eine main.rs
Datei im src
Verzeichnis. Der generic_handler.rs
kann verwendet werden, um einen generischen Event-Handler anzupassen. Die main.rs
Datei enthält Ihre Hauptanwendungslogik. Die Cargo.toml
Datei enthält Metadaten zu Ihrem Paket und listet dessen externe Abhängigkeiten auf.
Beispiel für einen Rust Lambda-Funktionscode
Das folgende Beispiel für einen Rust-Lambda-Funktionscode nimmt Informationen über eine Bestellung auf, erstellt eine Textdateiquittung und legt diese Datei in einen Amazon S3 S3-Bucket.
Beispiel main.rs
-Lambda-Funktion
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
}
Diese main.rs
-Datei enthält die folgenden Abschnitte des Codes:
-
use
Anweisungen: Verwenden Sie diese, um Rust-Kisten und -Methoden zu importieren, die Ihre Lambda-Funktion benötigt. -
#[derive(Deserialize, Serialize)]
: Definieren Sie die Form des erwarteten Eingabeereignisses in dieser Rust-Struktur. -
async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error>
: Dies ist die Haupthandler-Methode, die Ihre Hauptanwendungslogik enthält. -
async fn upload_receipt_to_s3 (...)
: Dies ist eine Hilfsmethode, auf die von derfunction_handler
Hauptmethode verwiesen wird. -
#[tokio::main]
: Dies ist ein Makro, das den Einstiegspunkt eines Rust-Programms markiert. Es richtet auch eine Tokio-Runtimeein, die es Ihrer main()
Methode ermöglicht,async
/zu verwendenawait
und asynchron auszuführen. -
async fn main() -> Result<(), Error>
: Diemain()
Funktion ist der Einstiegspunkt Ihres Codes. Darin spezifizieren wirfunction_handler
als Haupthandler-Methode.
Die folgende Cargo.toml
Datei gehört zu dieser Funktion.
[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"] }
Damit diese Funktion ordnungsgemäß funktioniert, muss ihre Ausführungsrolle die s3:PutObject
Aktion zulassen. Stellen Sie außerdem sicher, dass Sie die RECEIPT_BUCKET
-Umgebungsvariable definieren. Nach einem erfolgreichen Aufruf sollte der Amazon-S3-Bucket eine Empfangsdatei enthalten.
Gültige Klassendefinitionen für Rust-Handler
In den meisten Fällen haben Lambda-Handler-Signaturen, die Sie in Rust definieren, das folgende Format:
async fn function_handler(event: LambdaEvent<T>) -> Result<U, Error>
Für diesen Handler:
-
Der Name dieses Handlers ist
function_handler
. -
Die Singulareingabe für den Handler ist Event und hat den Typ
LambdaEvent<T>
.-
LambdaEvent
ist eine Verpackung, die aus der Kistelambda_runtime
stammt. Durch die Verwendung dieses Wrappers erhalten Sie Zugriff auf das Kontextobjekt, das Lambda-spezifische Metadaten wie die Anforderungs-ID des Aufrufs enthält. -
T
ist der deserialisierte Ereignistyp. Dies kann beispielsweise so seinserde_json::Value
, dass der Handler jede generische JSON-Eingabe aufnehmen kann. Alternativ kann dies ein Typ sein, z. B.ApiGatewayProxyRequest
wenn Ihre Funktion einen bestimmten, vordefinierten Eingabetyp erwartet.
-
-
Der Rückgabetyp des Handlers ist
Result<U, Error>
.-
U
ist der deserialisierte Ausgabetyp.U
muss denserde::Serialize
Traint implementieren, damit Lambda den Rückgabewert in JSON konvertieren kann. DiesU
kann beispielsweise ein einfacher Typ wieString
, oder eine benutzerdefinierte Struktur seinserde_json::Value
, sofern sie implementiert wird.Serialize
Wenn Ihr Code eine Ok (U) -Anweisung erreicht, deutet dies auf eine erfolgreiche Ausführung hin, und Ihre Funktion gibt einen Wert vom Typ zurückU
. -
Wenn Ihr Code auf einen Fehler stößt (d. h.
Err(Error)
), protokolliert Ihre Funktion den Fehler in Amazon CloudWatch und gibt eine Fehlerantwort vom Typ zurückError
.
-
In unserem Beispiel sieht die Handler-Signatur wie folgt aus:
async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error>
Andere gültige Handler-Signaturen können Folgendes enthalten:
-
Den
LambdaEvent
Wrapper weglassen — Wenn Sie ihn weglassenLambdaEvent
, verlieren Sie den Zugriff auf das Lambda-Kontextobjekt in Ihrer Funktion. Im Folgenden finden Sie ein Beispiel für diese Art von Signatur:async fn handler(event: serde_json::Value) -> Result<String, Error>
-
Verwenden des Einheitentyps als Eingabe — Für Rust können Sie den Einheitentyp verwenden, um eine leere Eingabe darzustellen. Dies wird häufig für Funktionen mit regelmäßigen, geplanten Aufrufen verwendet. Im Folgenden finden Sie ein Beispiel für diese Art von Signatur:
async fn handler(): ()) -> Result<Value, Error>
Namenskonventionen für Handler
Lambda-Handler in Rust haben keine strengen Namensbeschränkungen. Obwohl Sie einen beliebigen Namen für Ihren Handler verwenden können, sind Funktionsnamen in Rust im Allgemeinen in. snake_case
Für kleinere Anwendungen, wie in diesem Beispiel, können Sie eine einzige main.rs
Datei verwenden, die Ihren gesamten Code enthält. Bei größeren Projekten main.rs
sollte sie den Einstiegspunkt zu Ihrer Funktion enthalten, aber Sie können zusätzliche Dateien dafür verwenden, um Ihren Code in logische Module zu unterteilen. Beispielsweise könnten Sie die folgende Dateistruktur haben:
/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
Definieren Sie das Eingabeereignisobjekt und greifen Sie darauf zu
JSON ist das gebräuchlichste und standardmäßigste Eingabeformat für Lambda-Funktionen. In diesem Beispiel erwartet die Funktion eine Eingabe ähnlich der folgenden:
{
"order_id": "12345",
"amount": 199.99,
"item": "Wireless Headphones"
}
In Rust können Sie die Form des erwarteten Eingabeereignisses in einer Struktur definieren. In diesem Beispiel definieren wir die folgende Struktur zur Darstellung einesOrder
:
#[derive(Deserialize, Serialize)]
struct Order {
order_id: String,
amount: f64,
item: String,
}
Diese Struktur entspricht der erwarteten Eingabeform. In diesem Beispiel generiert das #[derive(Deserialize, Serialize)]
Makro automatisch Code für die Serialisierung und Deserialisierung. Das bedeutet, dass wir den generischen Eingabe-JSON-Typ mithilfe der Methode in unsere Struktur deserialisieren können. serde_json::from_value()
Dies wird in den ersten Zeilen des Handlers veranschaulicht:
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)?;
...
}
Sie können dann auf die Felder des Objekts zugreifen. Zum Beispiel holt order.order_id
den Wert von order_id
aus der ursprünglichen Eingabe.
Vordefinierte Eingabe-Ereignistypen
In der Kiste sind viele vordefinierte Eingabe-Ereignistypen verfügbar. aws_lambda_events
Zum Beispiel, wenn Sie beabsichtigen, Ihre Funktion mit API Gateway aufzurufen, einschließlich des folgenden Imports:
use aws_lambda_events::event::apigw::ApiGatewayProxyRequest;
Stellen Sie dann sicher, dass Ihr Haupthandler die folgende Signatur verwendet:
async fn handler(event: LambdaEvent<ApiGatewayProxyRequest>) -> Result<String, Error> {
let body = event.payload.body.unwrap_or_default();
...
}
Weitere Informationen zu anderen vordefinierten Eingabe-Ereignistypen finden Sie in der Kiste aws_lambda_events
Zugreifen auf und Verwenden des Lambda-Kontextobjekts
Das Lambda-Kontextobjekt enthält Informationen über Aufruf, Funktion und Ausführungsumgebung. In Rust enthält der Wrapper das Kontextobjekt. LambdaEvent
Sie können beispielsweise das Kontextobjekt verwenden, um die Anforderungs-ID des aktuellen Aufrufs mit dem folgenden Code abzurufen:
async fn function_handler(event: LambdaEvent<Value>) -> Result<String, Error> {
let request_id = event.context.request_id;
...
}
Weitere Informationen über das Kontextobjekt finden Sie unter Verwenden des Lambda-Kontextobjekts zum Abrufen von Rust-Funktionsinformationen.
Verwenden Sie die AWS SDK for Rust in Ihrem Handler
Oft verwenden Sie Lambda-Funktionen, um mit anderen AWS Ressourcen zu interagieren oder diese zu aktualisieren. Die einfachste Art, eine Schnittstelle zu diesen Ressourcen herzustellen, ist die AWS SDK for RustVerwendung von.
Um Ihrer Funktion SDK-Abhängigkeiten hinzuzufügen, fügen Sie sie zu Ihrer Cargo.toml
Datei hinzu. Wir empfehlen, nur die Bibliotheken hinzuzufügen, die Sie für Ihre Funktion benötigen. Im Beispielcode zuvor haben wir die verwendetaws_sdk_s3::Client
. In der Cargo.toml
Datei können Sie diese Abhängigkeit hinzufügen, indem Sie die folgende Zeile unter dem [dependencies]
Abschnitt hinzufügen:
aws-sdk-s3 = "1.78.0"
Anmerkung
Dies ist möglicherweise nicht die neueste Version. Wählen Sie die passende Version für Ihre Anwendung.
Importieren Sie dann die Abhängigkeiten direkt in Ihren Code:
use aws_sdk_s3::{Client, primitives::ByteStream};
Der Beispielcode initialisiert dann einen Amazon S3 S3-Client wie folgt:
let config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
let s3_client = Client::new(&config);
Nachdem Sie Ihren SDK-Client initialisiert haben, können Sie ihn verwenden, um mit anderen Diensten zu interagieren. AWS Der Beispielcode ruft die Amazon S3 PutObject
S3-API in der upload_receipt_to_s3
Hilfsfunktion auf.
Zugriff auf Umgebungsvariablen
In Ihrem Handler-Code können Sie mithilfe der env::var
-Methode auf beliebige Umgebungsvariablen verweisen. In diesem Beispiel verweisen wir mit der folgenden Codezeile auf die definierte RECEIPT_BUCKET
-Umgebungsvariable:
let bucket_name = env::var("RECEIPT_BUCKET")
.map_err(|_| "RECEIPT_BUCKET environment variable is not set")?;
Geteilten Zustand verwenden
Sie können geteilte Variablen deklarieren, die unabhängig vom Handler-Code Ihrer Lambda-Funktion sind. Diese Variablen können Ihnen helfen, Zustandsinformationen während des Init-Phase zu laden, bevor Ihre Funktion Ereignisse empfängt. Sie können beispielsweise den Code auf dieser Seite ändern, um den Shared State bei der Initialisierung des Amazon S3 S3-Clients zu verwenden, indem Sie die main
Funktion und die Handler-Signatur aktualisieren:
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
Bewährte Codemethoden für Rust-Lambda-Funktionen
Halten Sie sich an die Richtlinien in der folgenden Liste, um beim Erstellen Ihrer Lambda-Funktionen die besten Codierungspraktiken anzuwenden:
-
Trennen Sie den Lambda-Handler von Ihrer Core-Logik. Auf diese Weise können Sie eine Funktion zur besseren Prüfbarkeit von Einheiten schaffen.
-
Minimieren Sie die Komplexität Ihrer Abhängigkeiten. Ziehen Sie einfachere Frameworks vor, die sich schnell beim Start der Ausführungsumgebung laden lassen.
-
Minimieren Sie die Größe Ihres Bereitstellungspakets auf die für die Laufzeit erforderliche Größe. Dadurch verkürzt sich die Zeit, die für das Herunterladen und Entpacken Ihres Bereitstellungspakets vor dem Aufruf benötigt wird.
-
Nutzen Sie die Wiederverwendung der Ausführungsumgebung zur Verbesserung Ihrer Funktion. Initialisieren Sie SDK-Clients und Datenbankverbindungen außerhalb des Funktions-Handlers und speichern Sie statische Komponenten lokal im
/tmp
-Verzeichnis. Nachfolgende Aufrufe, die von derselben Instance Ihrer Funktion verarbeitet werden, können diese Ressourcen wiederverwenden. Dies spart Kosten durch Reduzierung der Funktionslaufzeit.Um potenzielle Datenlecks über Aufrufe hinweg zu vermeiden, verwenden Sie die Ausführungsumgebung nicht, um Benutzerdaten, Ereignisse oder andere Informationen mit Sicherheitsauswirkungen zu speichern. Wenn Ihre Funktion auf einem veränderbaren Zustand beruht, der nicht im Speicher innerhalb des Handlers gespeichert werden kann, sollten Sie für jeden Benutzer eine separate Funktion oder separate Versionen einer Funktion erstellen.
-
Verwenden Sie eine Keep-Alive-Direktive, um dauerhafte Verbindungen zu pflegen. Lambda bereinigt Leerlaufverbindungen im Laufe der Zeit. Der Versuch, eine Leerlaufverbindung beim Aufruf einer Funktion wiederzuverwenden, führt zu einem Verbindungsfehler. Um Ihre persistente Verbindung aufrechtzuerhalten, verwenden Sie die Keep-Alive-Direktive, die Ihrer Laufzeit zugeordnet ist. Ein Beispiel finden Sie unter Wiederverwenden von Verbindungen mit Keep-Alive in Node.js.
-
Verwenden Sie Umgebungsvariablen um Betriebsparameter an Ihre Funktion zu übergeben. Wenn Sie z. B. Daten in einen Amazon-S3-Bucket schreiben, anstatt den Bucket-Namen, in den Sie schreiben, hartzucodieren, konfigurieren Sie den Bucket-Namen als Umgebungsvariable.
-
Vermeiden Sie rekursive Aufrufe in Ihrer Lambda-Funktion, bei denen die Funktion sich selbst aufruft oder einen Prozess initiiert, der die Funktion erneut aufrufen kann. Dies kann zu unvorhergesehenen Mengen an Funktionsaufrufen führen und höhere Kosten zur Folge haben. Wenn Sie eine unbeabsichtigte Menge von Aufrufen feststellen, legen Sie die reservierte gleichzeitige Ausführung der Funktion auf
0
fest, um sofort alle Aufrufe der Funktion zu drosseln, während Sie den Code aktualisieren. -
Verwenden Sie APIs in Ihrem Lambda-Funktionscode nicht undokumentiert, nicht öffentlich. Für AWS Lambda verwaltete Laufzeiten führt Lambda regelmäßig Sicherheits- und Funktionsupdates für interne Lambda-Laufzeiten durch. APIs Diese internen API-Updates können abwärtsinkompatibel sein, was zu unbeabsichtigten Folgen wie Aufruffehlern führen kann, wenn Ihre Funktion von diesen nicht öffentlichen Daten abhängig ist. APIs Eine Liste der öffentlich verfügbaren Programme finden Sie in der API-Referenz. APIs
-
Schreiben Sie idempotenten Code. Das Schreiben idempotenter Code für Ihre Funktionen stellt sicher, dass doppelte Ereignisse auf die gleiche Weise behandelt werden. Ihr Code sollte Ereignisse ordnungsgemäß validieren und doppelte Ereignisse ordnungsgemäß behandeln. Weitere Informationen finden Sie unter Wie mache ich meine Lambda-Funktion idempotent?
.