Recently I have had the chance to muck around with the new DotNet Core in AWS Lambda. Here is a few things I have learnt and can hopefully save you the time and trouble of struggling over.
DotNet Core Version
AWS Love keeping AWS Lambda on annoyingly old versions of programming languages. In this case its not so bad and DotNet Core in AWS Supports version 1.0.1. What is interesting about dotnet core is that it is a compiled language so we can write stuff in 1.1.0 and it will still work. What wont work though is dependencies and libraries that are looking for certain framework DLL’s and namespaces that have been changed in the 1.1 release. In my experience it is best to stick with 1.0.1 (or 1.0.3, worked fine in my testing) to avoid all those weird issues.
Packaging and Invoking AWS Lambda Functions
If you include “Amazon.Lambda.Tools” in both the tools and dependencies sections of your project.json then you get some nice utilities that you can use to publish and test the lambda function from the command line. Here is an example of how to use the commands (Example’s are bash commands but are almost identical in CMD). Things in pairs of <>’s are arguments.
Packaging
dotnet lambda package -c <Debug OR Release> -f netcoreapp1.0
This command is used to package up a zip ready to chuck into AWS Lambda. Great way to provide your System Admins with a package for them to deploy in production. This zip can be found under bin<Debug OR Release>netcoreapp1.0Project.Name.zip
Auto Deploy/Run/Test a Function
If you have a AWS profile configured you can get lambda to automatically deploy the function for you. Best way to do this is to make a aws-lambda-tools-defaults.json in the root of your project that looks a little like this:
{
"profile":"default",
"region" : "ap-southeast-2",
"configuration" : "Debug",
"framework" : "netcoreapp1.0",
"function-runtime":"dotnetcore1.0",
"function-memory-size" : 512,
"function-timeout" : 15,
"function-handler" : "Optimal.AwesomeCode::Optimal.AwesomeCode.Handler::Handler",
"additional-files": []
}
Most of these options are pretty simple to fill out if you know about C# Lambda already. Otherwise read up on it here.
This will now let you run a simple commands to deploy and run your function.
dotnet lambda deploy-function -fn <awsLambdaFunctionName>
This command will compile and upload the function for you with no extra work. Which is nice of it. Note that it does not restore packages first so if you have changed your project.json you need to do a dotnet restore first.
dotnet lambda invoke-function -fn <awsLambdaFunctionName>
As you might have guessed this command invokes your fancy AWS Lambda function. You can also provide it some data with the –payload argument like so.
dotnet lambda invoke-function -fn <awsLambdaFunctionName> --payload {"Database":"111.111.111.0"...}
This means you have lots of options for testing your code during development or even writing command line based unit/integration tests!
Weird Dependency Issues
If you use the deploy-function command sometimes you will find a library you are using complains that it cannot find a class or namespace that it is expecting to exist. This is because the deploy-function command excludes some dll’s found in the runtimes folder. For example Npgsql (the main postgres library for dotnet) wants things from System.Net.NetworkInformation from netstandard1.3 which deploy-function decided we did not need. You can tell the lambda tools that we did actually want this file by including it in the additional-files section of the aws-lambda-tools-defaults.json like so:
{
"profile":"default",
"region" : "ap-southeast-2",
"configuration" : "Debug",
"framework" : "netcoreapp1.0",
"function-runtime":"dotnetcore1.0",
"function-memory-size" : 512,
"function-timeout" : 15,
"function-handler" : "Optimal.AwesomeCode::Optimal.AwesomeCode.Handler::Handler",
"additional-files": ["runtimes/linux/lib/netstandard1.3/System.Net.NetworkInformation.dll"]
}
Internet from Inside VPC’s
Not just limited to the C# Lambda but most of Lambda is that when deployed inside a VPC without a NAT your lambda function cannot reach services on the internet, like S3. This is fine as it is the expected behavior but the error message this generates is mostly likely to be that the function times out. If you find your function timing out with no other error messages then it is likely it cannot reach the service it is looking for.
A nice way to check is to quickly run the following function:
[code language=”csharp”] /// <summary>
/// Confirm that we have access to Internet.
/// </summary>
/// <returns>True iff an Internet connection can be established.</returns>
private bool TestInternetAccess() {
try {
HttpClient client = new HttpClient {Timeout = TimeSpan.FromSeconds(4)};
Task<HttpResponseMessage> getTask = client.GetAsync(new Uri("http://www.google.com"));
Task.WaitAll(getTask);
HttpResponseMessage getResult = getTask.Result;
if(!getResult.IsSuccessStatusCode) {
return false;
}
} catch(Exception e) {
return false;
}
return true;
}
[/code]That all I know for now! Hopefully that help with your adventures in AWS Lambda. Until next time.
Coffee to Code