Criando função AWS Lambda utilizando .Net Core
Processe um console window sem a necessidade de provisionar uma instância EC2
Afinal de contas, o que é o AWS Lambda?
Em poucas palavras, é um console window que processa um volume de informações, dentro de um servidor qualquer. E só.
Dá pra fazer bastante coisa num console window: processamento batch, bulk insert no sql, disparo de e-mails em massa, etc.
Por ser "apenas" um console window, a parte de servidor é abstraída. Isso significa que você não precisa se preocupar em configurar o Sistema Operacional, atualizações de segurança, patches, etc. Basta realizar o upload do executável.
Tudo isso denominado serverless
Essa facilidade serverless pode trazer outros problemas: é 15% mais lento e até 8x mais caro que uma instância EC2.
Entretanto, a vantagem é que não se paga por 720h mensais, mas sim pelo tempo de cada execução.
Se a sua necessidade é construir uma ferramenta de disparo de e-mails 5x no mês e cada execução demora 5 minutos, não pense 2x em utilizá-lo! Sai bem mais barato que reservar uma instância EC2 para um processo tão simples.
Histórias a parte, vamos ao que interessa! Iremos construir uma função ASW Lambda em .Net Core :-)
1. Criando a função na AWS
Acesse o console AWS https://console.aws.amazon.com/ , Lambda, Funções.
Clique no botão Criar Função.
Selecione a opção Criar do Zero...
Nome da função: minhaFuncao
Tempo de execução: .NET Core 3.1
Em Permissões, marque a opção Criar uma função com permissões básicas do Lambda. Clique no botão Criar função.
Por fim a função é criada.
No Visual Studio, crie um Projeto vazio do tipo Console Window, na linguagem .Net Core 3.1.
Program.cs:
using Amazon.Lambda.Core; using System; using System.Collections; using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using System.IO; using System.Net; namespace ConsoleLambda { public class Program { public static IConfigurationRoot Configuration; public static IConfiguration configuration { get; private set; } /// <summary> /// Este método só será executado durante o Debug. /// Não será invocado via execução AWS Lambda /// </summary> /// <param name="args"></param> static void Main(string[] args) { Console.WriteLine("Main!"); Program instancia = new Program(); LambdaContext lambda = new LambdaContext(); instancia.Handler(lambda); } private void ConfigureSettings() { Configuration = new ConfigurationBuilder() .SetBasePath(System.IO.Directory .GetParent(AppContext.BaseDirectory).FullName) .AddJsonFile("appsettings.json", optional: true) .Build(); // Não esqueça de habilitar a opção // "Copiar diretório de saída" para o arquivo appsettings.json, // caso contrário, Configuration sempre será NULL } public async Task Handler(ILambdaContext context) { this.ConfigureSettings(); StringBuilder sb = new StringBuilder(); sb.AppendLine("Hello World! My name is Lambda ;-)"); sb.AppendLine(""); sb.AppendLine("Variaveis de ambiente:"); foreach (DictionaryEntry de in Environment. GetEnvironmentVariables()) sb.AppendLine(de.Key + " = " + de.Value); sb.AppendLine("========================"); sb.AppendLine("ILambdaContext:"); sb.AppendLine("FunctionName: " + context.FunctionName); sb.AppendLine("RemainingTime: " + context.RemainingTime); sb.AppendLine("AwsRequestId: " + context.AwsRequestId); sb.AppendLine("FunctionVersion: " + context.FunctionVersion); sb.AppendLine("InvokedFunctionArn: " + context.InvokedFunctionArn); sb.AppendLine("LogGroupName: " + context.LogGroupName); sb.AppendLine("LogStreamName: " + context.LogStreamName); sb.AppendLine("MemoryLimitInMB: " + context.MemoryLimitInMB); sb.AppendLine("null: " + null); sb.AppendLine("========================"); sb.AppendLine("appsettings:"); sb.AppendLine("Versao: " + Configuration["versao"].ToString()); sb.AppendLine("Autor: " + Configuration["autor"].ToString()); Console.WriteLine(sb.ToString()); // Testando requisições internet (teste de firewall) var requisicaoWeb = WebRequest.CreateHttp("https://www.leobreda.net/"); requisicaoWeb.Method = "GET"; using (var resposta = requisicaoWeb.GetResponse()) { var streamDados = resposta.GetResponseStream(); StreamReader reader = new StreamReader(streamDados); object objResponse = reader.ReadToEnd(); Console.WriteLine(objResponse.ToString()); Console.ReadLine(); streamDados.Close(); resposta.Close(); } } } }
LambdaContext.cs (necessário para executar localmente o console window):
using Amazon.Lambda.Core; using System; namespace ConsoleLambda { public class LambdaContext : ILambdaContext { public string AwsRequestId => null; public IClientContext ClientContext => null; public string FunctionName => null; public string FunctionVersion => null; public ICognitoIdentity Identity => null; public string InvokedFunctionArn => null; public ILambdaLogger Logger => null; public string LogGroupName => null; public string LogStreamName => null; public int MemoryLimitInMB => 0; public TimeSpan RemainingTime => new DateTime().TimeOfDay; } }
appsettings.json (arquivo de configuração do console window):
{ "versao": "2020.10.20.a", "autor": "Leonardo Breda" }
NuGet:
Amazon.Lambda.Core Microsoft.Extensions.Configuration Microsoft.Extensions.Configuration.FileExtensions Microsoft.Extensions.Configuration.Json
Execute o console em debug para verificar se rodou com sucesso.
Faça a publicação do projeto...
Configuração: Release
Estrutura de destino: netcoreapp3.1
Tempo de execução de destino: linux-x64
Clique em publicar.
Vá até o diretório de destino e compacte todos os arquivos num único ZIP.
Volte até a função Lambda no console AWS. Em código da função, faça o upload do arquivo ZIP.
Na aba Permissões, Papel de execução, clique em Editar.
No campo manipulador, adote a seguinte nomenclatura:
Assembly::Namespace.Classe::Metodo
Clique em salvar.
Clique no botão Testar. Caso não tenha um teste associado, crie conforme a figura abaixo.
Clique novamente no botão Testar, onde deverá processar a função com sucesso .
No quadro resumo, é possível identificar o tempo de execução e memória RAM consumida.
No CloudWatch, é possível ver toda a saída produzida pelo console window.
E assim concluímos um aprendizado básico do AWS Lambda.