Aller au contenu

Lambda

De Banane Atomic

Links

Description

Serverless service / Function as a service allowing to run code without having to worry about underlying hardware and OS.
Event driven: the lambda is triggered by an event.
Pay only for what you use: per request and based on the duration of the code execution.

Use cases

  • Data transformation (Kinesis Data Stream as input)
  • File processing (when uploaded to S3 bucket)
  • Website backend microservice
  • Scheduled tasks

Bad use cases

  • Long running processes (timeout after 15mn)
  • Constant workload (no scalability and high cost)
  • Large code base (needed to be loaded at startup)
  • State management (lambda are stateless)

Anti-patterns

  • Monolithic function
    • increase package size
    • hard to enforce least privilege permissions
    • hard to upgrade, maintain and test
  • Recursion
    • endless loop
  • Orchestration
    • avoid complex workflow logic
    • ties lambda with other systems
    • instead consider AWS Step Functions or EventBridge
  • Chaining (synchronously invoke another lambda)
    • instead use EventBridge or QueueService
  • Waiting (synchronously call services or databases)
    • instead use asynchronous calls

Runtime

  • OS
  • Libraries
  • Programming language (.NET, Node.js, Python, Go, Ruby, Java)

Environnement variables

DOTNET_STARTUP_HOOKS ex: path to an assembly to inject logging

Wrapper scripts

Execute the wrapper on top of the runtime and the lambda function.

  • run shell commands and binaries

Use AWS_LAMBDA_EXEC_WRAPPER to point to your wrapper script.

Custom runtime

Provide your custom runtime.

  • unsupported programming language

Handler (entry point)

Method responsible for processing input events.

synchronous execution result returned to the calling app
asynchronous execution result sent to the configured destination otherwise lost

C# executable assembly

Using the C# 9's top-level statements feature, you generate an executable assembly which will be run by the Lambda. You provide Lambda only with the name of the executable assembly to run.

var handler = async (string argument1, ILambdaContext context) => { };

// bootstrap the Lambda runtime and pass it the handler method
await LambdaBootstrapBuilder.Create(handler, new DefaultLambdaJsonSerializer()).Build().RunAsync();

Setting up your .NET development environment

# install the VS project template
dotnet new install Amazon.Lambda.Templates

# install the command line tools
dotnet tool install -g Amazon.Lambda.Tools

C# class library

Function.cs
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace MyProject;

public class Function
{
    public string FunctionHandler(string input, ILambdaContext context)
    {
        return input.ToUpper();
    }
}
aws-lambda-tools-defaults.json
{
  "Information": [ ],
  "profile": "MyAwsProfile",
  "region": "eu-central-1",
  "configuration": "Release",
  "function-architecture": "x86_64",
  "function-runtime": "dotnet8",
  "function-memory-size": 512,
  "function-timeout": 30,
  "function-handler": "MyProject::MyProject.Function::FunctionHandler"
}
Properties/launchSettings.json
{
  "profiles": {
    "Mock Lambda Test Tool": {
      "commandName": "Executable",
      "commandLineArgs": "--port 5050",
      "workingDirectory": ".\\bin\\$(Configuration)\\net8.0",
      "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-8.0.exe"
    }
  }
}

Debug locally

C# class library

On VS, if the extension AWS Toolkit is installed you have the AWS .NET Mock Lambda Test Tool available.
A debug configuration is created for you lambda.

Properties\launchSettings.json
{
  "profiles": {
    "Mock Lambda Test Tool": {
      "commandName": "Executable",
      "commandLineArgs": "--port 5050",
      "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-8.0.exe",
      "workingDirectory": ".\\bin\\$(Configuration)\\net8.0"
    }
  }
}

C# executable assembly

You have to create the debug configuration file for you lambda.

Properties\launchSettings.json
{
  "profiles": {
    "Mock Lambda Test Tool": {
      "commandName": "Executable",
      "commandLineArgs": "--port 5050",
      "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-8.0.exe",
      "workingDirectory": ".\\bin\\$(Configuration)\\net8.0",
      "environmentVariables": {
        "AWS_LAMBDA_RUNTIME_API": "localhost:5050",
        "AWS_PROFILE": "MyProfile",
        "AWS_REGION": "us-east-1"
      }
    }
  }
}

Deployment

dotnet lambda deploy-function [AssemblyName] --profile [Profile]

Call a lambda from code

var jsonSerializerOptions = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    Converters = { new JsonStringEnumConverter() }
};

var amazonLambdaClient = new AmazonLambdaClient();

var request = new InvokeRequest
{
    FunctionName = functionName,
    Payload = JsonSerializer.Serialize(myObject, jsonSerializerOptions),
    LogType = LogType.Tail
};
var response = await this.amazonLambdaClient.InvokeAsync(request);

if(response.HttpStatusCode == System.Net.HttpStatusCode.OK)
{
    var payload = Encoding.ASCII.GetString(response.Payload.ToArray()); // to debug only
    var result = JsonSerializer.Deserialize<AwsJobResult<LambdaJob>>(response.Payload, jsonSerializerOptions);
}

Errors

Could not find the specified handler assembly with the file name LambdaTest

The Lambda on AWS has wrongly set the handler to LambdaTest.
AWS - Lambda - Functions - select your function - Code tab - Runtime settings - Edit - change the Handler