{"@attributes":{"version":"2.0"},"channel":{"title":"DEV Community: Maxime David","description":"The latest articles on DEV Community by Maxime David (@maxday).","link":"https:\/\/dev.to\/maxday","image":{"url":"https:\/\/media2.dev.to\/dynamic\/image\/width=90,height=90,fit=cover,gravity=auto,format=auto\/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F976571%2Fb6a30eed-0453-4c82-82e3-ea7de3a2fdd5.jpeg","title":"DEV Community: Maxime David","link":"https:\/\/dev.to\/maxday"},"language":"en","item":[{"title":"Rust on AWS App Runner - Part2","pubDate":"Tue, 05 Sep 2023 14:01:00 +0000","link":"https:\/\/dev.to\/aws-builders\/rust-on-aws-app-runner-part2-17d2","guid":"https:\/\/dev.to\/aws-builders\/rust-on-aws-app-runner-part2-17d2","description":"<p>Hey hey hey \ud83c\udf55!<\/p>\n\n<p>This is the second part of this series, make sure you've already read <a href=\"https:\/\/dev.to\/aws-builders\/rust-on-aws-app-runner-part1-4hpp\">the first part<\/a> :)<\/p>\n\n<p>In the first part, we saw how to create a basic Rust API with a <code>GET \/pizza<\/code> endpoint to retrieve the list of pizza.<\/p>\n\n<p>In this part, let's see how to containerize our app!<\/p>\n\n<h2>\n  \n  \n  Let's create our container\n<\/h2>\n\n<p>Since AWS App Runner is a fully managed container application service, we definitely need a container!<\/p>\n\n<p>In this section, we will see how to build that container thanks to <code>Docker<\/code> using a <code>Dockerfile<\/code>.<\/p>\n\n<p>A <code>Dockerfile<\/code> is a text file that contains all the commands needed to build our container, it's often compared to a recipe.<\/p>\n\n<h2>\n  \n  \n  Rust as the base image\n<\/h2>\n\n<p>Let's start with<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight docker\"><code><span class=\"k\">FROM<\/span><span class=\"s\"> rust:slim-bullseye<\/span>\n<span class=\"k\">WORKDIR<\/span><span class=\"s\"> \/app<\/span>\n<span class=\"k\">COPY<\/span><span class=\"s\"> .\/ \/app<\/span>\n<span class=\"k\">RUN <\/span>cargo build <span class=\"nt\">--release<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The first line describes the base image that we want to use, here the official <code>rust<\/code> one. <\/p>\n\n<p>This is really convenient since we don't have to install <code>rust<\/code> or <code>cargo<\/code>: both are already installed in this base image.<\/p>\n\n<p>Then we define the current working directory, here <code>\/app<\/code><\/p>\n\n<p>Then we copy our sources (<code>src<\/code> + <code>Cargo.toml<\/code> + <code>Cargo.lock<\/code>) into the container.<\/p>\n\n<p>Finally we build our API directly inside the container, in release mode, to be sure to have a production-ready binary.<\/p>\n\n<p>Great, we now have our binary ready in our image!<\/p>\n\n<p>But wait, we also have <code>rust<\/code>, <code>cargo<\/code> and a bunch of useless tools at runtime. <\/p>\n\n<p>It was convenient to use the official <code>rust<\/code> image <strong>to build<\/strong>, but we don't need it anymore for the <strong>runtime<\/strong>. Fortunately, Docker supports <strong>multi stage builds<\/strong>.<\/p>\n\n<h2>\n  \n  \n  Multi-stage builds\n<\/h2>\n\n<p>We can specify a base image to build and another one to run! That's exactly what we want!<\/p>\n\n<p>The idea here is to have the smallest possible image so the cold start would be extremely fast. That's why we are going to use a <code>distroless<\/code> base image.<\/p>\n\n<p>Those images are built by Google and contain almost nothing: no <code>bash<\/code>, no <code>ssh<\/code>, no utility tools which makes the image extremely small.<\/p>\n\n<p>Let's modify our Dockerfile:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight docker\"><code><span class=\"k\">FROM<\/span><span class=\"w\"> <\/span><span class=\"s\">rust:slim-bullseye<\/span><span class=\"w\"> <\/span><span class=\"k\">AS<\/span><span class=\"w\"> <\/span><span class=\"s\">BUILD<\/span>\n<span class=\"k\">COPY<\/span><span class=\"s\"> .\/ \/app<\/span>\n<span class=\"k\">RUN <\/span>cargo build <span class=\"nt\">--release<\/span>\n\n<span class=\"k\">FROM<\/span><span class=\"s\"> gcr.io\/distroless\/cc-debian10<\/span>\n<span class=\"k\">COPY<\/span><span class=\"s\"> --from=BUILD \/app\/target\/release\/app-runner-rust \/ <\/span>\n<span class=\"k\">CMD<\/span><span class=\"s\"> [\".\/app-runner-rust\"]<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Here we name our first image <code>BUILD<\/code> so we can reference that later. Then from the distroless image, we copy our binary from the <code>BUILD<\/code> image! Super convenient! I love Docker :D<\/p>\n\n<p>Our runtime image is just the <code>distroless base image<\/code> + <code>rust binary<\/code><\/p>\n\n<p>Let's finally build it with <code>docker build . -t maxday\/app-runner<\/code><\/p>\n\n<p>Let's check for our image size: <code>docker images | grep maxday\/app-runner<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>docker images | <span class=\"nb\">grep <\/span>maxday\/app-runner\nmaxday\/app-runner                                          latest          e278afc78403   3 minutes ago    20.1MB\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>20.1MB!!! \ud83e\udd2f Extremely small!<\/strong><\/p>\n\n<p>Woot woot! We now have a ready to deploy container!<\/p>\n\n<h2>\n  \n  \n  Local test\n<\/h2>\n\n<p>Before deploying, let's make sure everything looks fine by running it locally and calling our <code>GET \/pizza<\/code> endpoint.<\/p>\n\n<p>You can run your newly built docker image with:<br><br>\n<code>docker run -d -p 8080:8080 maxday\/app-runner<\/code><\/p>\n\n<ul>\n<li>\n<code>-d<\/code> means <code>detached<\/code> so the container runs in the background<\/li>\n<li>\n<code>-p 8080:8080<\/code> means that you're bridging the host port 8080 to the container port 8080.<\/li>\n<\/ul>\n\n<p>You can check that your container is up and running with:<br><br>\n<code>docker ps<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>docker ps\nCONTAINER ID   IMAGE               COMMAND               CREATED          STATUS          PORTS                    NAMES\ne5d8978ee6ee   maxday\/app-runner   <span class=\"s2\">\".\/app-runner-rust\"<\/span>   53 seconds ago   Up 53 seconds   0.0.0.0:8080-&gt;8080\/tcp   pedantic_kare\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Now you can curl the endpoint:<br><br>\n<code>curl http:\/\/localhost:8080\/pizza<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>curl localhost:8080\/pizza\n<span class=\"o\">[{<\/span><span class=\"s2\">\"name\"<\/span>:<span class=\"s2\">\"Margherita\"<\/span>,<span class=\"s2\">\"toppings\"<\/span>:[<span class=\"s2\">\"tomato\"<\/span>,<span class=\"s2\">\"fior di latte\"<\/span><span class=\"o\">]<\/span>,<span class=\"s2\">\"price\"<\/span>:10<span class=\"o\">}<\/span>,<span class=\"o\">{<\/span><span class=\"s2\">\"name\"<\/span>:<span class=\"s2\">\"Veggie\"<\/span>,<span class=\"s2\">\"toppings\"<\/span>:[<span class=\"s2\">\"green peppers\"<\/span>,<span class=\"s2\">\"onion\"<\/span>,<span class=\"s2\">\"mushrooms\"<\/span><span class=\"o\">]<\/span>,<span class=\"s2\">\"price\"<\/span>:12<span class=\"o\">}]<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Awesome! \ud83c\udf89<\/p>\n\n<p><strong>Our container is now ready to be used by AWS App Runner.<\/strong> <\/p>\n\n<p>See you next week for the final episode of this series to deploy it!<\/p>\n\n<p><strong>Like this content? Consider following me for more!<\/strong><\/p>\n\n<p>A question? Feel free to use the comment section \u2b07\ufe0f<\/p>\n\n<p>You can find me on <a href=\"https:\/\/www.linkedin.com\/in\/maxday\/\">LinkedIn<\/a>, <a href=\"https:\/\/www.youtube.com\/@maxday_coding\">YouTube<\/a> and <a href=\"https:\/\/twitter.com\/_maxday\">Twitter<\/a>!<\/p>\n\n"},{"title":"Rust on AWS App Runner - Part1","pubDate":"Mon, 21 Aug 2023 14:36:51 +0000","link":"https:\/\/dev.to\/aws-builders\/rust-on-aws-app-runner-part1-4hpp","guid":"https:\/\/dev.to\/aws-builders\/rust-on-aws-app-runner-part1-4hpp","description":"<p>Hey hey hey \ud83c\udf55!<\/p>\n\n<p>Over the past few months, I've been advocating for Rust on AWS Lambda a lot!<\/p>\n\n<p>Here is a quick recap in case you missed it!<\/p>\n\n<ul>\n<li>\n<a href=\"https:\/\/www.youtube.com\/watch?v=Idys2BAmqIU\">Live coding<\/a>  a AWS Lambda in Rust with TDD<\/li>\n<li>\n<a href=\"https:\/\/github.com\/maxday\/lambda-perf\">Lambda-Perf tool<\/a> where Rust is killing the cold start game<\/li>\n<\/ul>\n\n<p>By the way, we're almost at 256 \u2b50\ufe0f which is \ud83e\udd2f for a side project! I'm sure we can do it!<\/p>\n\n<ul>\n<li>\n<a href=\"https:\/\/www.youtube.com\/live\/5ptACic_FJQ?feature=share&amp;t=255\">Rust Linz Meetup<\/a> where I gave a talk about Serverless + Rust<\/li>\n<\/ul>\n\n<p>But as you may know, serverless is NOT only about AWS Lambda. If you need compute, <strong>AWS App Runner<\/strong> might be a great fit!<\/p>\n\n<h2>\n  \n  \n  AWS App Runner\n<\/h2>\n\n<p>If you see Lambda as <code>functions as a service<\/code> you can see <br>\nApp Runner as <code>containers as a service<\/code>.<\/p>\n\n<p>It means that you can focus on <\/p>\n\n<ul>\n<li>building your app<\/li>\n<li>containerized it (ie: Docker image)<\/li>\n<\/ul>\n\n<p>and AWS will scale it for you, including to zero.<\/p>\n\n<p>It also means that you will experience a cold start when no containers are up or when you need to handle more traffic.<\/p>\n\n<p>Similarly to AWS Lambda, Rust would be a great candidate for AWS App Runner if we manage to build a tiny container which starts extremely fast! <\/p>\n\n<p>Annnnnnd that's what we are going to try to do in the series of blog post! <\/p>\n<h2>\n  \n  \n  Ready? Let's gooooooo! \ud83c\udf89\n<\/h2>\n\n<ul>\n<li><strong>Part1 - Create a simple Rust API - this blog post<\/strong><\/li>\n<li>Part2 - Containerize it! (and make it small)<\/li>\n<li>Part3 - Deploy it to AWS App Runner<\/li>\n<\/ul>\n<h2>\n  \n  \n  Part 1 - Create a simple Rust API\n<\/h2>\n\n<p>In this part, we will focus on building a simple Rust service.<\/p>\n\n<p>Let's bootstrap the project using <code>cargo<\/code> <br>\nand run <code>cargo new pizza-rust --bin<\/code> <br>\n(oh yeah we're going to talk about \ud83c\udf55)<\/p>\n\n<p>You should now have this file structure:<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--AMbpPlqn--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/43q551m441gvqrunlczx.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--AMbpPlqn--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/43q551m441gvqrunlczx.png\" alt=\"file structure\" width=\"129\" height=\"97\"><\/a><\/p>\n<h2>\n  \n  \n  Dependency\n<\/h2>\n\n<p>There are multiple web framework crates in Rust but one the most commonly used is <code>actix_web<\/code> so let's use this one!<\/p>\n\n<p>We're also going to need <code>serde<\/code> to serialize and deserialize our pizzas.<\/p>\n\n<p>Finally, for testing purpose, we're going to use both <code>actix-rt<\/code> abd <code>actix-test<\/code><\/p>\n<h2>\n  \n  \n  main.rs\n<\/h2>\n\n<p>Our main function will look like this:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"nd\">#[actix_web::main]<\/span>\n<span class=\"k\">async<\/span> <span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"nn\">std<\/span><span class=\"p\">::<\/span><span class=\"nn\">io<\/span><span class=\"p\">::<\/span><span class=\"nb\">Result<\/span><span class=\"o\">&lt;<\/span><span class=\"p\">()<\/span><span class=\"o\">&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nn\">HttpServer<\/span><span class=\"p\">::<\/span><span class=\"nf\">new<\/span><span class=\"p\">(<\/span><span class=\"k\">move<\/span> <span class=\"p\">||<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nn\">App<\/span><span class=\"p\">::<\/span><span class=\"nf\">new<\/span><span class=\"p\">()<\/span>\n        <span class=\"nf\">.service<\/span><span class=\"p\">(<\/span><span class=\"n\">pizza_service<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">})<\/span>\n    <span class=\"nf\">.bind<\/span><span class=\"p\">((<\/span><span class=\"s\">\"0.0.0.0\"<\/span><span class=\"p\">,<\/span> <span class=\"mi\">8080<\/span><span class=\"p\">))<\/span><span class=\"o\">?<\/span>\n    <span class=\"nf\">.run<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">.await<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Here we've defined a very minimal web server, listening on 8080 and using the not-yet-defined <code>pizza_service<\/code><\/p>\n\n<h2>\n  \n  \n  Test first!\n<\/h2>\n\n<p>Before going too far in the actual code, let's write our unit test first.<br>\nWhen we hit \/pizza, we want to receive a JSON array of pizza.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"nd\">#[cfg(test)]<\/span>\n<span class=\"k\">mod<\/span> <span class=\"n\">tests<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">use<\/span> <span class=\"k\">crate<\/span><span class=\"p\">::{<\/span><span class=\"n\">pizza_service<\/span><span class=\"p\">,<\/span> <span class=\"n\">Pizza<\/span><span class=\"p\">};<\/span>\n    <span class=\"k\">use<\/span> <span class=\"nn\">actix_web<\/span><span class=\"p\">::{<\/span><span class=\"n\">App<\/span><span class=\"p\">,<\/span> <span class=\"n\">web<\/span><span class=\"p\">};<\/span>\n\n    <span class=\"nd\">#[actix_rt::test]<\/span>\n    <span class=\"k\">async<\/span> <span class=\"k\">fn<\/span> <span class=\"nf\">test<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n\n        <span class=\"c1\">\/\/ define a test pizza<\/span>\n        <span class=\"k\">let<\/span> <span class=\"n\">pizzas<\/span> <span class=\"o\">=<\/span> <span class=\"nd\">vec!<\/span><span class=\"p\">[<\/span>\n            <span class=\"nn\">Pizza<\/span><span class=\"p\">::<\/span><span class=\"nf\">new<\/span><span class=\"p\">(<\/span><span class=\"s\">\"pizzaTest\"<\/span><span class=\"p\">,<\/span> <span class=\"nd\">vec!<\/span><span class=\"p\">[<\/span><span class=\"s\">\"topping0\"<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"topping1\"<\/span><span class=\"p\">],<\/span> <span class=\"mi\">1234<\/span><span class=\"p\">),<\/span>\n        <span class=\"p\">];<\/span>\n\n        <span class=\"c1\">\/\/ define our in-memory db<\/span>\n        <span class=\"k\">let<\/span> <span class=\"n\">app_data<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">web<\/span><span class=\"p\">::<\/span><span class=\"nn\">Data<\/span><span class=\"p\">::<\/span><span class=\"nf\">new<\/span><span class=\"p\">(<\/span><span class=\"n\">pizzas<\/span><span class=\"p\">);<\/span>\n\n        <span class=\"c1\">\/\/ define our test server<\/span>\n        <span class=\"k\">let<\/span> <span class=\"n\">srv<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">actix_test<\/span><span class=\"p\">::<\/span><span class=\"nf\">start<\/span><span class=\"p\">(<\/span><span class=\"k\">move<\/span> <span class=\"p\">||<\/span> \n            <span class=\"nn\">App<\/span><span class=\"p\">::<\/span><span class=\"nf\">new<\/span><span class=\"p\">()<\/span>\n            <span class=\"nf\">.app_data<\/span><span class=\"p\">(<\/span><span class=\"n\">app_data<\/span><span class=\"nf\">.clone<\/span><span class=\"p\">())<\/span>\n            <span class=\"nf\">.service<\/span><span class=\"p\">(<\/span><span class=\"n\">pizza_service<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">);<\/span>\n\n        <span class=\"c1\">\/\/ perform the request<\/span>\n        <span class=\"k\">let<\/span> <span class=\"n\">req<\/span> <span class=\"o\">=<\/span> <span class=\"n\">srv<\/span><span class=\"nf\">.get<\/span><span class=\"p\">(<\/span><span class=\"s\">\"\/pizza\"<\/span><span class=\"p\">);<\/span>\n        <span class=\"k\">let<\/span> <span class=\"k\">mut<\/span> <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">req<\/span><span class=\"nf\">.send<\/span><span class=\"p\">()<\/span><span class=\"k\">.await<\/span><span class=\"nf\">.unwrap<\/span><span class=\"p\">();<\/span>\n        <span class=\"nd\">assert!<\/span><span class=\"p\">(<\/span><span class=\"n\">response<\/span><span class=\"nf\">.status<\/span><span class=\"p\">()<\/span><span class=\"nf\">.is_success<\/span><span class=\"p\">());<\/span>\n        <span class=\"k\">let<\/span> <span class=\"n\">result_pizza<\/span> <span class=\"o\">=<\/span> <span class=\"n\">response<\/span><span class=\"py\">.json<\/span><span class=\"p\">::<\/span><span class=\"o\">&lt;<\/span><span class=\"nb\">Vec<\/span><span class=\"o\">&lt;<\/span><span class=\"n\">Pizza<\/span><span class=\"o\">&gt;&gt;<\/span><span class=\"p\">()<\/span><span class=\"k\">.await<\/span><span class=\"nf\">.unwrap<\/span><span class=\"p\">();<\/span>\n\n        <span class=\"c1\">\/\/ assert the result<\/span>\n        <span class=\"nd\">assert!<\/span><span class=\"p\">(<\/span><span class=\"n\">result_pizza<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span><span class=\"py\">.name<\/span> <span class=\"o\">==<\/span> <span class=\"s\">\"pizzaTest\"<\/span><span class=\"p\">);<\/span>\n        <span class=\"nd\">assert!<\/span><span class=\"p\">(<\/span><span class=\"n\">result_pizza<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span><span class=\"py\">.toppings<\/span> <span class=\"o\">==<\/span> <span class=\"nd\">vec!<\/span><span class=\"p\">[<\/span><span class=\"s\">\"topping0\"<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"topping1\"<\/span><span class=\"p\">]);<\/span>\n        <span class=\"nd\">assert!<\/span><span class=\"p\">(<\/span><span class=\"n\">result_pizza<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span><span class=\"py\">.price<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">1234<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Back to main.rs\n<\/h2>\n\n<p>Finally, let's modify our code to satisfy our test<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"c1\">\/\/ let's create our pizza structure, making sure we can serialize and deserialize it!<\/span>\n<span class=\"nd\">#[derive(Serialize,<\/span> <span class=\"nd\">Deserialize)]<\/span>\n<span class=\"k\">struct<\/span> <span class=\"n\">Pizza<\/span> <span class=\"p\">{<\/span>\n    <span class=\"n\">name<\/span><span class=\"p\">:<\/span> <span class=\"nb\">String<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">toppings<\/span><span class=\"p\">:<\/span> <span class=\"nb\">Vec<\/span><span class=\"o\">&lt;<\/span><span class=\"nb\">String<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">price<\/span><span class=\"p\">:<\/span> <span class=\"nb\">i32<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"c1\">\/\/ simple Pizza constructor<\/span>\n<span class=\"k\">impl<\/span> <span class=\"n\">Pizza<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">fn<\/span> <span class=\"nf\">new<\/span><span class=\"p\">(<\/span><span class=\"n\">name<\/span><span class=\"p\">:<\/span> <span class=\"o\">&amp;<\/span><span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">toppings<\/span><span class=\"p\">:<\/span> <span class=\"nb\">Vec<\/span><span class=\"o\">&lt;&amp;<\/span><span class=\"nb\">str<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">,<\/span> <span class=\"n\">price<\/span><span class=\"p\">:<\/span> <span class=\"nb\">i32<\/span><span class=\"p\">)<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"n\">Pizza<\/span> <span class=\"p\">{<\/span>\n        <span class=\"n\">Pizza<\/span> <span class=\"p\">{<\/span>\n            <span class=\"n\">name<\/span><span class=\"p\">:<\/span> <span class=\"n\">name<\/span><span class=\"nf\">.to_string<\/span><span class=\"p\">(),<\/span>\n            <span class=\"n\">toppings<\/span><span class=\"p\">:<\/span> <span class=\"n\">toppings<\/span><span class=\"nf\">.iter<\/span><span class=\"p\">()<\/span><span class=\"nf\">.map<\/span><span class=\"p\">(|<\/span><span class=\"n\">s<\/span><span class=\"p\">|<\/span> <span class=\"n\">s<\/span><span class=\"nf\">.to_string<\/span><span class=\"p\">())<\/span><span class=\"nf\">.collect<\/span><span class=\"p\">(),<\/span>\n            <span class=\"n\">price<\/span><span class=\"p\">,<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"c1\">\/\/ define our GET endpoint<\/span>\n<span class=\"nd\">#[get(<\/span><span class=\"s\">\"\/pizza\"<\/span><span class=\"nd\">)]<\/span>\n<span class=\"k\">async<\/span> <span class=\"k\">fn<\/span> <span class=\"nf\">pizza_service<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">:<\/span> <span class=\"nn\">web<\/span><span class=\"p\">::<\/span><span class=\"n\">Data<\/span><span class=\"o\">&lt;<\/span><span class=\"nb\">Vec<\/span><span class=\"o\">&lt;<\/span><span class=\"n\">Pizza<\/span><span class=\"o\">&gt;&gt;<\/span><span class=\"p\">)<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"k\">impl<\/span> <span class=\"n\">Responder<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/just returning the JSON representation of our pizzas<\/span>\n    <span class=\"nn\">HttpResponse<\/span><span class=\"p\">::<\/span><span class=\"nf\">Ok<\/span><span class=\"p\">()<\/span><span class=\"nf\">.json<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nd\">#[actix_web::main]<\/span>\n<span class=\"k\">async<\/span> <span class=\"k\">fn<\/span> <span class=\"nf\">main<\/span><span class=\"p\">()<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"nn\">std<\/span><span class=\"p\">::<\/span><span class=\"nn\">io<\/span><span class=\"p\">::<\/span><span class=\"nb\">Result<\/span><span class=\"o\">&lt;<\/span><span class=\"p\">()<\/span><span class=\"o\">&gt;<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ our fresh pizzas<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">pizzas<\/span> <span class=\"o\">=<\/span> <span class=\"nd\">vec!<\/span><span class=\"p\">[<\/span>\n        <span class=\"nn\">Pizza<\/span><span class=\"p\">::<\/span><span class=\"nf\">new<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Margherita\"<\/span><span class=\"p\">,<\/span> <span class=\"nd\">vec!<\/span><span class=\"p\">[<\/span><span class=\"s\">\"tomato\"<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"fior di latte\"<\/span><span class=\"p\">],<\/span> <span class=\"mi\">10<\/span><span class=\"p\">),<\/span>\n        <span class=\"nn\">Pizza<\/span><span class=\"p\">::<\/span><span class=\"nf\">new<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Veggie\"<\/span><span class=\"p\">,<\/span> <span class=\"nd\">vec!<\/span><span class=\"p\">[<\/span><span class=\"s\">\"green peppers\"<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"onion\"<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"mushrooms\"<\/span><span class=\"p\">],<\/span> <span class=\"mi\">12<\/span><span class=\"p\">),<\/span>\n    <span class=\"p\">];<\/span>\n\n    <span class=\"c1\">\/\/ in-memory db<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">app_data<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">web<\/span><span class=\"p\">::<\/span><span class=\"nn\">Data<\/span><span class=\"p\">::<\/span><span class=\"nf\">new<\/span><span class=\"p\">(<\/span><span class=\"n\">pizzas<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"nn\">HttpServer<\/span><span class=\"p\">::<\/span><span class=\"nf\">new<\/span><span class=\"p\">(<\/span><span class=\"k\">move<\/span> <span class=\"p\">||<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nn\">App<\/span><span class=\"p\">::<\/span><span class=\"nf\">new<\/span><span class=\"p\">()<\/span>\n        <span class=\"nf\">.app_data<\/span><span class=\"p\">(<\/span><span class=\"n\">app_data<\/span><span class=\"nf\">.clone<\/span><span class=\"p\">())<\/span>\n        <span class=\"nf\">.service<\/span><span class=\"p\">(<\/span><span class=\"n\">pizza_service<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">})<\/span>\n    <span class=\"nf\">.bind<\/span><span class=\"p\">((<\/span><span class=\"s\">\"0.0.0.0\"<\/span><span class=\"p\">,<\/span> <span class=\"mi\">8080<\/span><span class=\"p\">))<\/span><span class=\"o\">?<\/span>\n    <span class=\"nf\">.run<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">.await<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>That's it!<br>\nOur test is now passing:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>cargo <span class=\"nb\">test\n   <\/span>Compiling app-runner-rust v1.0.0 <span class=\"o\">(<\/span>\/rust<span class=\"o\">)<\/span>\n    Finished <span class=\"nb\">test<\/span> <span class=\"o\">[<\/span>unoptimized + debuginfo] target<span class=\"o\">(<\/span>s<span class=\"o\">)<\/span> <span class=\"k\">in <\/span>1.27s\n     Running unittests src\/main.rs <span class=\"o\">(<\/span>target\/debug\/deps\/app_runner_rust-46a4a4cb852eb0c3<span class=\"o\">)<\/span>\n\nrunning 1 <span class=\"nb\">test\ntest <\/span>tests::test ... ok\n\n<span class=\"nb\">test <\/span>result: ok. 1 passed<span class=\"p\">;<\/span> 0 failed<span class=\"p\">;<\/span> 0 ignored<span class=\"p\">;<\/span> 0 measured<span class=\"p\">;<\/span> 0 filtered out<span class=\"p\">;<\/span> finished <span class=\"k\">in <\/span>0.01s\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Final check\n<\/h2>\n\n<p>Let's run our API with <code>cargo run<\/code> <br>\nand hit our endpoint <code>curl -i http:\/\/localhost:8080\/pizza<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>curl <span class=\"nt\">-i<\/span> http:\/\/localhost:8080\/pizza\nHTTP\/1.1 200 OK\ncontent-length: 150\ncontent-type: application\/json\n<span class=\"nb\">date<\/span>: Sun, 20 Aug 2023 00:26:27 GMT\n\n<span class=\"o\">[{<\/span><span class=\"s2\">\"name\"<\/span>:<span class=\"s2\">\"Margherita\"<\/span>,<span class=\"s2\">\"toppings\"<\/span>:[<span class=\"s2\">\"tomato\"<\/span>,<span class=\"s2\">\"fior di latte\"<\/span><span class=\"o\">]<\/span>,<span class=\"s2\">\"price\"<\/span>:10<span class=\"o\">}<\/span>,<span class=\"o\">{<\/span><span class=\"s2\">\"name\"<\/span>:<span class=\"s2\">\"Veggie\"<\/span>,<span class=\"s2\">\"toppings\"<\/span>:[<span class=\"s2\">\"green peppers\"<\/span>,<span class=\"s2\">\"onion\"<\/span>,<span class=\"s2\">\"mushrooms\"<\/span><span class=\"o\">]<\/span>,<span class=\"s2\">\"price\"<\/span>:12<span class=\"o\">}]<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Voila! \ud83c\udf55<\/p>\n\n<p>Our API is now ready to be containerized and that's the topic of the next blog post in this series! <\/p>\n\n<p>\ud83d\udc4b Stay tunned for part 2 next week!<\/p>\n\n<p>You can find me on <a href=\"https:\/\/www.linkedin.com\/in\/maxday\/\">LinkedIn<\/a>, <a href=\"https:\/\/www.youtube.com\/@maxday_coding\">YouTube<\/a> and <a href=\"https:\/\/twitter.com\/_maxday\">Twitter<\/a>!<\/p>\n\n"},{"title":"How I Discovered That the AWS Lambda Runtime Might Be Written in Go","pubDate":"Wed, 02 Aug 2023 18:28:23 +0000","link":"https:\/\/dev.to\/aws-builders\/how-i-discovered-that-the-aws-lambda-runtime-might-be-written-in-go-3i9l","guid":"https:\/\/dev.to\/aws-builders\/how-i-discovered-that-the-aws-lambda-runtime-might-be-written-in-go-3i9l","description":"<p>Have you ever wondered how your Lambda function code is triggered?<\/p>\n\n<p>Each runtime has to conform to the <a href=\"https:\/\/docs.aws.amazon.com\/lambda\/latest\/dg\/runtimes-api.html\" rel=\"noopener noreferrer\">AWS Lambda runtime API<\/a>.<\/p>\n\n<p>In managed runtimes, you don't need to take care of that; that's the whole point of using a managed runtime! AWS takes care of that for you.<\/p>\n\n<p><strong>But how?<\/strong><\/p>\n\n<p>It's hard to say because it's not clearly documented. However, while I was conducting some unrelated experiments, I made a very cool discovery! <br>\nI think you'll find it interesting too!<\/p>\n\n<p>If you're working with Go and care about performance, you might want to look at some important metrics, such as:<\/p>\n\n<ul>\n<li>the number of allocations <\/li>\n<li>the time taken for each init() functions<\/li>\n<\/ul>\n\n<p>To do so, you need to setup a environment variable:<br><br>\n<code>GODEBUG<\/code> to <code>inittrace=1<\/code>.<\/p>\n\n<p>And tada \ud83c\udf89!<\/p>\n\n<p>In addition to information about the binary I wanted to test, I'm now able to see traces from another binary, which seems to be the one from AWS that conforms to the runtime API.<\/p>\n\n<p>Here is an example of the output \ud83d\udc40\ud83d\udc40\ud83d\udc40<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>init internal\/bytealg @0.008 ms, 0 ms clock, 0 bytes, 0 allocs\n...\ninit go.amzn.com\/lambda\/fatalerror @3.7 ms, 0.031 ms clock, 336 bytes, 2 allocs\n...\ninit go.amzn.com\/lambda\/interop @6.5 ms, 0.023 ms clock, 1128 bytes, 32 allocs\ninit go.amzn.com\/lambda\/telemetry @6.5 ms, 0.067 ms clock, 16 bytes, 1 allocs\ninit go.amzn.com\/lambda\/core @6.6 ms, 0.007 ms clock, 224 bytes, 12 allocs\ninit go.amzn.com\/lambda\/rapi\/rendering @6.7 ms, 0.086 ms clock, 16 bytes, 1 allocs\ninit go.amzn.com\/lambda\/rapi\/handler @6.8 ms, 0 ms clock, 256 bytes, 2 allocs\ninit go.amzn.com\/lambda\/rapid @6.8 ms, 0.099 ms clock, 16 bytes, 1 allocs\n...\nINIT_START Runtime Version: nodejs:18.v9 Runtime Version ARN: arn:aws:lambda:us-east-1::runtime:7d5f06b69c951da8a48b926ce280a9daf2e8bb1a74fc4a2672580c787d608206\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Here, we can clearly see some explicit package names coming from AWS. <\/p>\n\n<p>Another important thing to note is that those logs are output BEFORE the <code>INIT_START<\/code> log line, which provides further evidence that it might be how AWS Lambda is managing your code!<\/p>\n\n<p>Voila! \ud83c\udf89<br>\nWhat do you think?<\/p>\n\n<p>You can find me on <a href=\"https:\/\/www.linkedin.com\/in\/maxday\/\" rel=\"noopener noreferrer\">LinkedIn<\/a> and <a href=\"https:\/\/twitter.com\/_maxday\" rel=\"noopener noreferrer\">Twitter<\/a>!<\/p>\n\n","category":["aws","lambda","performance"]},{"title":"Benchmarking Rust for Serverless","pubDate":"Fri, 14 Apr 2023 14:35:19 +0000","link":"https:\/\/dev.to\/aws-builders\/benchmarking-rust-for-serverless-36ck","guid":"https:\/\/dev.to\/aws-builders\/benchmarking-rust-for-serverless-36ck","description":"<p>Let's start with two <strong>very<\/strong> important questions:<\/p>\n\n<p>(1)  Why should I care to <strong>benchmark<\/strong> Rust since it's already super fast?<\/p>\n\n<p>That's the question we'll try to answer in this post! <\/p>\n\n<p>(2) Will there be a \ud83c\udf55 demo?<\/p>\n\n<p>Of course, you know that I'm a true \ud83c\udf55\ud83c\udf55\ud83c\udf55 lover!<\/p>\n\n<h3>\n  \n  \n  What's so special about Serverless?\n<\/h3>\n\n<p>Benchmarking is not specific to serverless. But in serverless components, such as AWS Lambda functions, performance really matters for two main reasons:<\/p>\n\n<ul>\n<li><p><strong>Cold start duration<\/strong> (good news, Rust is really performant as you can see in <a href=\"https:\/\/maxday.github.io\/lambda-perf\">my daily updated benchmark<\/a>)<\/p><\/li>\n<li><p><strong>Runtime duration<\/strong>, as AWS is billing <strong>per millisecond<\/strong>.<\/p><\/li>\n<\/ul>\n\n<p>Let's see how we can measure and improve this runtime duration using benchmarks!<\/p>\n\n<h3>\n  \n  \n  What are we going to benchmark?\n<\/h3>\n\n<p>Let's take a very simple example:<br><br>\n<code>a function which returns the pizza of the day.<\/code> \ud83c\udf55 (I told you)<\/p>\n\n<p>We will compare two different implementations:<\/p>\n\n<ul>\n<li>one with HashMap - <code>std::collections::HashMap<\/code>\n<\/li>\n<li>one with Vec - <code>std::vec::Vec<\/code>\n<\/li>\n<\/ul>\n\n<p><em>(if you don't know much about Rust, you might wish to take a look at some basic Rust code before we start, like the Rust book or my <a href=\"https:\/\/youtube.com\/@maxday_coding\">Rust Youtube channel<\/a> \ud83d\ude07)<\/em><\/p>\n\n<p>First, let's define our <code>PizzaStore<\/code> trait:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">pub<\/span> <span class=\"k\">trait<\/span> <span class=\"n\">PizzaStore<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">fn<\/span> <span class=\"nf\">get_pizza_of_the_day<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"k\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">day_index<\/span><span class=\"p\">:<\/span> <span class=\"nb\">i32<\/span><span class=\"p\">)<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"o\">&amp;<\/span><span class=\"nb\">str<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>And our first implementation with HashMap:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"c1\">\/\/ let's make sure we don't initialize a new HashMap each time<\/span>\n<span class=\"k\">pub<\/span> <span class=\"k\">struct<\/span> <span class=\"n\">PizzaHashMap<\/span><span class=\"o\">&lt;<\/span><span class=\"nv\">'a<\/span><span class=\"o\">&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"n\">cache<\/span><span class=\"p\">:<\/span> <span class=\"n\">HashMap<\/span><span class=\"o\">&lt;<\/span><span class=\"nb\">i32<\/span><span class=\"p\">,<\/span> <span class=\"o\">&amp;<\/span><span class=\"nv\">'a<\/span> <span class=\"nb\">str<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">,<\/span> \n<span class=\"p\">}<\/span>\n\n<span class=\"k\">impl<\/span><span class=\"o\">&lt;<\/span><span class=\"nv\">'a<\/span><span class=\"o\">&gt;<\/span> <span class=\"n\">PizzaHashMap<\/span><span class=\"o\">&lt;<\/span><span class=\"nv\">'a<\/span><span class=\"o\">&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">pub<\/span> <span class=\"k\">fn<\/span> <span class=\"nf\">new<\/span><span class=\"p\">()<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"k\">Self<\/span> <span class=\"p\">{<\/span>\n        <span class=\"n\">PizzaHashMap<\/span> <span class=\"p\">{<\/span>\n            <span class=\"n\">cache<\/span><span class=\"p\">:<\/span> <span class=\"nn\">HashMap<\/span><span class=\"p\">::<\/span><span class=\"nf\">from<\/span><span class=\"p\">([<\/span>\n                <span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"margherita\"<\/span><span class=\"p\">),<\/span>\n                <span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"deluxe\"<\/span><span class=\"p\">),<\/span>\n                <span class=\"p\">(<\/span><span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"veggie\"<\/span><span class=\"p\">),<\/span>\n                <span class=\"p\">(<\/span><span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"mushrooms\"<\/span><span class=\"p\">),<\/span>\n                <span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"bacon\"<\/span><span class=\"p\">),<\/span>\n                <span class=\"p\">(<\/span><span class=\"mi\">5<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"four cheese\"<\/span><span class=\"p\">),<\/span>\n                <span class=\"p\">(<\/span><span class=\"mi\">6<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"pepperoni\"<\/span><span class=\"p\">),<\/span>\n                <span class=\"c1\">\/\/ what's your favorite?<\/span>\n            <span class=\"p\">]),<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">impl<\/span><span class=\"o\">&lt;<\/span><span class=\"nv\">'a<\/span><span class=\"o\">&gt;<\/span> <span class=\"n\">PizzaStore<\/span> <span class=\"k\">for<\/span> <span class=\"n\">PizzaHashMap<\/span><span class=\"o\">&lt;<\/span><span class=\"nv\">'a<\/span><span class=\"o\">&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ let's get the pizza of the day from the cache (HashMap)<\/span>\n    <span class=\"k\">fn<\/span> <span class=\"nf\">get_pizza_of_the_day<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"k\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">day_index<\/span><span class=\"p\">:<\/span> <span class=\"nb\">i32<\/span><span class=\"p\">)<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"o\">&amp;<\/span><span class=\"nb\">str<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">match<\/span> <span class=\"k\">self<\/span><span class=\"py\">.cache<\/span><span class=\"nf\">.get<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">day_index<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nf\">Some<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">pizza<\/span><span class=\"p\">)<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"n\">pizza<\/span><span class=\"p\">,<\/span>\n            <span class=\"nb\">None<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"nd\">panic!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"could not find the pizza\"<\/span><span class=\"p\">),<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Writing our first benchmark\n<\/h3>\n\n<p>There are quite some crates to create benchmarks but we'll use <code>criterion<\/code> here.<br>\nLet's start by creating a <code>benches<\/code> folder containing a <code>benchmark.rs<\/code> file and add our first criterion:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">fn<\/span> <span class=\"nf\">criterion_hashmap<\/span><span class=\"p\">(<\/span><span class=\"n\">c<\/span><span class=\"p\">:<\/span> <span class=\"o\">&amp;<\/span><span class=\"k\">mut<\/span> <span class=\"n\">Criterion<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"k\">mut<\/span> <span class=\"n\">rng<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">rand<\/span><span class=\"p\">::<\/span><span class=\"nf\">thread_rng<\/span><span class=\"p\">();<\/span>\n    <span class=\"c1\">\/\/ we create the cache outside of the bench function so only one HashMap will be created<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">pizza_store_hashmap<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">PizzaHashMap<\/span><span class=\"p\">::<\/span><span class=\"nf\">new<\/span><span class=\"p\">();<\/span>\n    <span class=\"c1\">\/\/ we call get_pizza_of_the_day with a random day index<\/span>\n    <span class=\"n\">c<\/span><span class=\"nf\">.bench_function<\/span><span class=\"p\">(<\/span><span class=\"s\">\"with hashmap\"<\/span><span class=\"p\">,<\/span> <span class=\"p\">|<\/span><span class=\"n\">b<\/span><span class=\"p\">|<\/span> <span class=\"n\">b<\/span><span class=\"nf\">.iter<\/span><span class=\"p\">(||<\/span> <span class=\"n\">pizza_store_hashmap<\/span><span class=\"nf\">.get_pizza_of_the_day<\/span><span class=\"p\">(<\/span><span class=\"n\">rng<\/span><span class=\"nf\">.gen_range<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"o\">..<\/span><span class=\"mi\">7<\/span><span class=\"p\">))));<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>We also need a bench group (as we will add more criterion later)<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"nd\">criterion_group!<\/span><span class=\"p\">(<\/span><span class=\"n\">benches<\/span><span class=\"p\">,<\/span> <span class=\"n\">criterion_hashmap<\/span><span class=\"p\">);<\/span>\n<span class=\"nd\">criterion_main!<\/span><span class=\"p\">(<\/span><span class=\"n\">benches<\/span><span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>That's it! Let's run it with <code>cargo bench<\/code><\/p>\n\n<p>By default, it runs our function for about 5seconds (that's about 300M+ iterations)<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code>     <span class=\"n\">Running<\/span> <span class=\"n\">benches<\/span><span class=\"o\">\/<\/span><span class=\"n\">benchmark<\/span><span class=\"nf\">.rs<\/span> <span class=\"p\">(<\/span><span class=\"n\">target<\/span><span class=\"o\">\/<\/span><span class=\"n\">release<\/span><span class=\"o\">\/<\/span><span class=\"n\">deps<\/span><span class=\"o\">\/<\/span><span class=\"n\">benchmark<\/span><span class=\"o\">-<\/span><span class=\"mi\">2<\/span><span class=\"n\">f28819806c8c7c9<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">with<\/span> <span class=\"n\">hashmap<\/span>            <span class=\"n\">time<\/span><span class=\"p\">:<\/span>   <span class=\"p\">[<\/span><span class=\"mf\">13.069<\/span> <span class=\"n\">ns<\/span> <span class=\"mf\">13.090<\/span> <span class=\"n\">ns<\/span> <span class=\"mf\">13.114<\/span> <span class=\"n\">ns<\/span><span class=\"p\">]<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Left and right values are lower and upper bounds. <\/p>\n\n<p>The number in the middle is the best estimation on how long each iteration is likely to take. <\/p>\n\n<p><em>Note that those 3 numbers are extremely alike. This won't be the case if you're depending on networking for instance.<\/em><\/p>\n\n<h3>\n  \n  \n  Second implementation: with Vec\n<\/h3>\n\n<p>Let's create a different implementation using Vec instead of using HashMap using the following code.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">pub<\/span> <span class=\"k\">struct<\/span> <span class=\"n\">PizzaVec<\/span><span class=\"o\">&lt;<\/span><span class=\"nv\">'a<\/span><span class=\"o\">&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"n\">cache<\/span><span class=\"p\">:<\/span> <span class=\"nb\">Vec<\/span><span class=\"o\">&lt;&amp;<\/span><span class=\"nv\">'a<\/span> <span class=\"nb\">str<\/span><span class=\"o\">&gt;<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">impl<\/span><span class=\"o\">&lt;<\/span><span class=\"nv\">'a<\/span><span class=\"o\">&gt;<\/span> <span class=\"n\">PizzaVec<\/span><span class=\"o\">&lt;<\/span><span class=\"nv\">'a<\/span><span class=\"o\">&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">pub<\/span> <span class=\"k\">fn<\/span> <span class=\"nf\">new<\/span><span class=\"p\">()<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"k\">Self<\/span> <span class=\"p\">{<\/span>\n        <span class=\"n\">PizzaVec<\/span> <span class=\"p\">{<\/span>\n            <span class=\"n\">cache<\/span><span class=\"p\">:<\/span> <span class=\"nd\">vec!<\/span><span class=\"p\">[<\/span><span class=\"s\">\"margherita\"<\/span><span class=\"p\">,<\/span><span class=\"s\">\"deluxe\"<\/span><span class=\"p\">,<\/span><span class=\"s\">\"veggie\"<\/span><span class=\"p\">,<\/span><span class=\"s\">\"mushrooms\"<\/span><span class=\"p\">,<\/span><span class=\"s\">\"bacon\"<\/span><span class=\"p\">,<\/span><span class=\"s\">\"four cheese\"<\/span><span class=\"p\">,<\/span><span class=\"s\">\"pepperoni\"<\/span><span class=\"p\">],<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">impl<\/span><span class=\"o\">&lt;<\/span><span class=\"nv\">'a<\/span><span class=\"o\">&gt;<\/span> <span class=\"n\">PizzaStore<\/span> <span class=\"k\">for<\/span> <span class=\"n\">PizzaVec<\/span><span class=\"o\">&lt;<\/span><span class=\"nv\">'a<\/span><span class=\"o\">&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">fn<\/span> <span class=\"nf\">get_pizza_of_the_day<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"k\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">day_index<\/span><span class=\"p\">:<\/span> <span class=\"nb\">i32<\/span><span class=\"p\">)<\/span> <span class=\"k\">-&gt;<\/span> <span class=\"o\">&amp;<\/span><span class=\"nb\">str<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">match<\/span> <span class=\"k\">self<\/span><span class=\"py\">.cache<\/span><span class=\"nf\">.get<\/span><span class=\"p\">(<\/span><span class=\"n\">day_index<\/span> <span class=\"k\">as<\/span> <span class=\"nb\">usize<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nf\">Some<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">pizza<\/span><span class=\"p\">)<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"n\">pizza<\/span><span class=\"p\">,<\/span>\n            <span class=\"nb\">None<\/span> <span class=\"k\">=&gt;<\/span> <span class=\"nd\">panic!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"could not find the pizza\"<\/span><span class=\"p\">),<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Let's create a new criterion so we can compare (that's the goal of benchmarks!)<br><br>\nBack in <code>benchmark.rs<\/code> we can add<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">fn<\/span> <span class=\"nf\">criterion_vec<\/span><span class=\"p\">(<\/span><span class=\"n\">c<\/span><span class=\"p\">:<\/span> <span class=\"o\">&amp;<\/span><span class=\"k\">mut<\/span> <span class=\"n\">Criterion<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"k\">mut<\/span> <span class=\"n\">rng<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">rand<\/span><span class=\"p\">::<\/span><span class=\"nf\">thread_rng<\/span><span class=\"p\">();<\/span>\n    <span class=\"k\">let<\/span> <span class=\"n\">pizza_store_vec<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">PizzaVec<\/span><span class=\"p\">::<\/span><span class=\"nf\">new<\/span><span class=\"p\">();<\/span>\n    <span class=\"n\">c<\/span><span class=\"nf\">.bench_function<\/span><span class=\"p\">(<\/span><span class=\"s\">\"with vector\"<\/span><span class=\"p\">,<\/span> <span class=\"p\">|<\/span><span class=\"n\">b<\/span><span class=\"p\">|<\/span> <span class=\"n\">b<\/span><span class=\"nf\">.iter<\/span><span class=\"p\">(||<\/span> <span class=\"n\">pizza_store_vec<\/span><span class=\"nf\">.get_pizza_of_the_day<\/span><span class=\"p\">(<\/span><span class=\"n\">rng<\/span><span class=\"nf\">.gen_range<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"o\">..<\/span><span class=\"mi\">7<\/span><span class=\"p\">))));<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>and update our group to include this new criterion:<br>\n<\/p>\n\n<p><code>criterion_group!(benches, criterion_hashmap, criterion_vec);<\/code><br>\n<\/p>\n\n<p>so we can re-run our  benchmarks with : <code>cargo bench<\/code><\/p>\n\n<p>and check the result!<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"n\">with<\/span> <span class=\"n\">hashmap<\/span>            <span class=\"n\">time<\/span><span class=\"p\">:<\/span>   <span class=\"p\">[<\/span><span class=\"mf\">13.096<\/span> <span class=\"n\">ns<\/span> <span class=\"mf\">13.117<\/span> <span class=\"n\">ns<\/span> <span class=\"mf\">13.141<\/span> <span class=\"n\">ns<\/span><span class=\"p\">]<\/span>\n<span class=\"n\">with<\/span> <span class=\"n\">vector<\/span>             <span class=\"n\">time<\/span><span class=\"p\">:<\/span>   <span class=\"p\">[<\/span><span class=\"mf\">7.5832<\/span> <span class=\"n\">ns<\/span> <span class=\"mf\">7.5958<\/span> <span class=\"n\">ns<\/span> <span class=\"mf\">7.6097<\/span> <span class=\"n\">ns<\/span><span class=\"p\">]<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>By replacing our HashMap with a Vec, our program is now running almost <strong>twice as fast<\/strong>! <\/p>\n\n<p>This is a great reminder on how the data structure choice is really important depending on the use case \ud83d\ude07<\/p>\n\n<h3>\n  \n  \n  Ok great, but how does it translate to Serverless?\n<\/h3>\n\n<p>Two AWS Lambda Functions have been deployed embedding each one of the implementations.<\/p>\n\n<p>Each lambda function calls <strong>10_000_000 times<\/strong> <code>get_pizza_of_the_day<\/code> <\/p>\n\n<p>In <code>us-east-1<\/code> with <code>128MB<\/code>, here are the results:<\/p>\n\n<div class=\"table-wrapper-paragraph\"><table>\n<thead>\n<tr>\n<th>Implementation<\/th>\n<th>Runtime duration<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>HashMap<\/td>\n<td>267.92 ms<\/td>\n<\/tr>\n<tr>\n<td>Vec<\/td>\n<td>87.98 ms \ud83e\udd2f\ud83e\udd2f<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/div>\n\n<p>That's it! <\/p>\n\n<p>Of course this was a simple example but I hope I've convinced you to use benchmarks to optimize your code!<\/p>\n\n<p><strong>Bonus question:<\/strong> where does this overhead come from? <\/p>\n\n<p>Stay tuned for the next blog post about <strong>Rust profiling<\/strong>!<\/p>\n\n<p>\u2764\ufe0f \u2764\ufe0f \u2764\ufe0f Did you like this content? \u2764\ufe0f \u2764\ufe0f \u2764\ufe0f <\/p>\n\n<ul>\n<li>Follow me on <a href=\"https:\/\/linkedin.com\/in\/maxday\">LinkedIn<\/a> &amp; <a href=\"https:\/\/twitter.com\/_maxday\">Twitter<\/a>\n<\/li>\n<li>Check my <a href=\"https:\/\/youtube.com\/@maxday_coding\">Rust Youtube channel<\/a>\n<\/li>\n<li>Share with your friends &lt;3<\/li>\n<\/ul>\n\n","category":["serverless","rust","lambda","aws"]},{"title":"RUST: How to test println!() ?","pubDate":"Tue, 22 Nov 2022 21:07:02 +0000","link":"https:\/\/dev.to\/maxday\/rust-how-to-test-println--1bd8","guid":"https:\/\/dev.to\/maxday\/rust-how-to-test-println--1bd8","description":"<p>Let's say we want to test that a function is correctly outputting something.<\/p>\n\n<p>Our function may looks like this simple example: print n times the name given in parameter.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">fn<\/span> <span class=\"nf\">greeting<\/span><span class=\"p\">(<\/span><span class=\"n\">nb<\/span><span class=\"p\">:<\/span> <span class=\"nb\">i32<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"p\">:<\/span> <span class=\"o\">&amp;<\/span><span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">for<\/span> <span class=\"n\">_<\/span> <span class=\"k\">in<\/span> <span class=\"mi\">0<\/span><span class=\"o\">..<\/span><span class=\"n\">nb<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"hi {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>   \n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>How to test it? \ud83e\udd14 It looks hard.<\/p>\n\n<p>One easy way is to refactor our code using a <code>Trait<\/code>.<br>\nYou can see Traits as interfaces.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">trait<\/span> <span class=\"n\">Logger<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">fn<\/span> <span class=\"k\">log<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"k\">mut<\/span> <span class=\"k\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span><span class=\"p\">:<\/span> <span class=\"nb\">String<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Then, let's define a <code>struct<\/code> which implements this <code>trait<\/code>.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">struct<\/span> <span class=\"n\">ConsoleLogger<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">impl<\/span> <span class=\"n\">Logger<\/span> <span class=\"k\">for<\/span> <span class=\"n\">ConsoleLogger<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">fn<\/span> <span class=\"k\">log<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"k\">mut<\/span> <span class=\"k\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span><span class=\"p\">:<\/span> <span class=\"nb\">String<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nd\">println!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"{}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Great! Now we can refactor our <code>greeting<\/code> function to use this <code>trait<\/code>.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">fn<\/span> <span class=\"nf\">greeting<\/span><span class=\"p\">(<\/span><span class=\"n\">nb<\/span><span class=\"p\">:<\/span> <span class=\"nb\">i32<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"p\">:<\/span> <span class=\"o\">&amp;<\/span><span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">logger<\/span><span class=\"p\">:<\/span> <span class=\"o\">&amp;<\/span><span class=\"k\">mut<\/span> <span class=\"k\">dyn<\/span> <span class=\"n\">Logger<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">for<\/span> <span class=\"n\">_<\/span> <span class=\"k\">in<\/span> <span class=\"mi\">0<\/span><span class=\"o\">..<\/span><span class=\"n\">nb<\/span> <span class=\"p\">{<\/span>\n        <span class=\"n\">logger<\/span><span class=\"nf\">.log<\/span><span class=\"p\">(<\/span><span class=\"nd\">format!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"hi {}\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"p\">));<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Ok but how this is helpful for testing?<\/p>\n\n<p>Well, now, in tests, we could define a new struct with a different implementation for our trait. <\/p>\n\n<p>Here, instead of outputting our strings using <code>println!<\/code> we will store those in a <code>Vec&lt;String&gt;<\/code><br>\nThis way, it will be super easy to assert that our values are valid.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"k\">struct<\/span> <span class=\"nf\">TestLogger<\/span><span class=\"p\">(<\/span><span class=\"nb\">Vec<\/span><span class=\"o\">&lt;<\/span><span class=\"nb\">String<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">);<\/span>\n\n<span class=\"k\">impl<\/span> <span class=\"n\">Logger<\/span> <span class=\"k\">for<\/span> <span class=\"n\">TestLogger<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">fn<\/span> <span class=\"k\">log<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"k\">mut<\/span> <span class=\"k\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span><span class=\"p\">:<\/span> <span class=\"nb\">String<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n            <span class=\"k\">self<\/span><span class=\"na\">.0<\/span><span class=\"nf\">.push<\/span><span class=\"p\">(<\/span><span class=\"n\">value<\/span><span class=\"p\">);<\/span>\n        <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>And we can finally test:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight rust\"><code><span class=\"nd\">#[test]<\/span>\n<span class=\"k\">fn<\/span> <span class=\"nf\">greeting_test<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">let<\/span> <span class=\"k\">mut<\/span> <span class=\"n\">test_logger<\/span> <span class=\"o\">=<\/span> <span class=\"nn\">TestLogger<\/span><span class=\"p\">::<\/span><span class=\"nf\">default<\/span><span class=\"p\">();<\/span>\n    <span class=\"nf\">greeting<\/span><span class=\"p\">(<\/span><span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"maxday\"<\/span><span class=\"p\">,<\/span> <span class=\"o\">&amp;<\/span><span class=\"k\">mut<\/span> <span class=\"n\">test_logger<\/span><span class=\"p\">);<\/span>\n    <span class=\"nd\">assert_eq!<\/span><span class=\"p\">(<\/span><span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"n\">test_logger<\/span><span class=\"na\">.0<\/span><span class=\"nf\">.len<\/span><span class=\"p\">());<\/span>\n    <span class=\"nd\">assert_eq!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"hi maxday\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">test_logger<\/span><span class=\"na\">.0<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]);<\/span>\n    <span class=\"nd\">assert_eq!<\/span><span class=\"p\">(<\/span><span class=\"s\">\"hi maxday\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">test_logger<\/span><span class=\"na\">.0<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]);<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Voila! \ud83c\udf89<\/p>\n\n<p>Full code here: <a href=\"https:\/\/gist.github.com\/maxday\/ae3c9f219c35c228dadd5359def5a833\">https:\/\/gist.github.com\/maxday\/ae3c9f219c35c228dadd5359def5a833<\/a><\/p>\n\n<p>\ud83d\ude80 \ud83d\ude80 \ud83d\ude80 If you want more Rust, feel free to check my new YouTube channel here: <a href=\"https:\/\/youtube.com\/@maxday_coding\">https:\/\/youtube.com\/@maxday_coding<\/a><\/p>\n\n","category":["rust","testing","programming"]}]}}