Introduction : Pourquoi Rust pour le Serverless est une révolution
\n\nL'architecture serverless est depuis longtemps devenue la norme pour construire des applications évolutives et économiques. Cependant, le choix traditionnel des langages (Python, Node.js, Java) se heurte souvent au problème du démarrage à froid et à une consommation mémoire élevée. Rust, avec son coût zéro des abstractions et l'absence de ramasse-miettes, offre une solution révolutionnaire. Dans cet article, nous allons voir comment créer, configurer et déployer des fonctions serverless en Rust pour AWS Lambda, de l'installation des outils aux versions de production.
\n\nÀ la fin de cet article, vous serez capable de :
\n- \n
- Configurer l'environnement de développement Rust + AWS Lambda \n
- Écrire une fonction efficace avec gestion des événements \n
- Optimiser le fichier binaire pour un temps de démarrage à froid minimal \n
- Déployer la fonction dans AWS avec Cargo Lambda \n
Préparation de l'environnement : Cargo Lambda et AWS CLI
\n\nPour travailler avec Rust sur AWS Lambda, nous avons besoin d'un outil spécial : cargo-lambda. Il automatise la compilation, les tests et le déploiement. Installons-le via Cargo :
cargo install cargo-lambda\n\nAssurez-vous également d'avoir installé aws-cli (configuré avec des clés IAM) et Docker (pour les tests locaux). Créons un nouveau projet :
cargo lambda new my-rust-lambda\ncd my-rust-lambda\n\nLa commande crée une structure de base avec un fichier Cargo.toml et src/main.rs. Notez les dépendances dans Cargo.toml :
[package]\nname = "my-rust-lambda"\nversion = "0.1.0"\nedition = "2021"\n\n[dependencies]\nlambda_runtime = "0.11"\ntokio = { version = "1", features = ["macros", "rt-multi-thread"] }\nserde = { version = "1.0", features = ["derive"] }\nserde_json = "1.0"\ntracing = { version = "0.1", features = ["log"] }\ntracing-subscriber = { version = "0.3", features = ["fmt"] }\n\nLa bibliothèque clé est lambda_runtime. Elle fournit le trait LambdaHandler que nous allons implémenter.
Écriture de la première fonction : traitement d'une requête API Gateway
\n\nConsidérons un scénario classique : une fonction qui reçoit un JSON avec le nom d'un utilisateur et retourne un message de bienvenue. Ouvrons src/main.rs et écrivons le code suivant :
use lambda_runtime::{run, service_fn, Error, LambdaEvent};\nuse serde::{Deserialize, Serialize};\n\n#[derive(Deserialize)]\nstruct Request {\n name: String,\n}\n\n#[derive(Serialize)]\nstruct Response {\n message: String,\n}\n\nasync fn function_handler(event: LambdaEvent<Request>) -> Result<Response, Error> {\n let name = event.payload.name;\n let message = format!("Bonjour, {} ! Tu viens de lancer Rust sur Lambda !", name);\n Ok(Response { message })\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Error> {\n tracing_subscriber::fmt()\n .with_max_level(tracing::Level::INFO)\n .init();\n\n run(service_fn(function_handler)).await\n}\n\nAnalysons les points clés :
\n- \n
LambdaEvent<Request>— une structure contenant le corps de la requête et le contexte d'exécution. \n #[tokio::main]— le runtime asynchrone nécessaire au fonctionnement du runtime Lambda. \n serde— pour la désérialisation du JSON entrant et la sérialisation de la réponse. \n
Testons localement :
\n\ncargo lambda watch\n\nEnsuite, dans un autre terminal :
\n\ncargo lambda invoke --data-ascii '{"name": "Alexis"}'\n\nVous devriez voir : {"message":"Bonjour, Alexis ! Tu viens de lancer Rust sur Lambda !"}
Optimisation du démarrage à froid et de la taille du binaire
\n\nLe principal avantage de Rust est un démarrage à froid minimal. Cependant, pour y parvenir, il faut compiler correctement le bi