Funções Serverless em TypeScript: nível avançado no AWS Lambda
\n\nA arquitetura Serverless tornou-se o padrão de facto para construir aplicações escaláveis e econômicas. AWS Lambda é um dos serviços mais populares para implementar funções serverless. Se a sintaxe básica e os gatilhos (API Gateway, S3, DynamoDB) já foram dominados, é hora de técnicas avançadas. Neste artigo, abordaremos os principais aspectos do desenvolvimento profissional de funções Lambda em TypeScript: desde a otimização do cold start até a integração com VPC e o uso de padrões complexos.
\n\n1. Otimização do Cold Start e gerenciamento de memória
\n\nO cold start é o principal inimigo do desempenho de aplicações serverless. Em TypeScript, esse problema é agravado pela etapa de compilação. Vamos considerar três métodos principais de combate.
\n\n1.1. Redução do tamanho do pacote de deploy
\nUse esbuild para compilar em vez do tsc padrão. Ele realiza tree-shaking e minificação, reduzindo o tamanho do bundle em 5 a 10 vezes. Exemplo de configuração para serverless.yml:
plugins:\n - serverless-esbuild\ncustom:\n esbuild:\n bundle: true\n minify: true\n sourcemap: false\n target: 'node18'\n exclude: ['aws-sdk'] # SDK já está no ambiente Lambda\n\n1.2. Uso de Provisioned Concurrency
\nPara funções críticas em relação à latência (por exemplo, que processam requisições de API), configure Provisioned Concurrency. Isso mantém um número definido de contêineres "quentes" sempre em execução:
\n\nfunctions:\n apiHandler:\n handler: src/handler.apiHandler\n provisionedConcurrency: 5 # Sempre 5 instâncias prontas\n\n1.3. Otimização de imports e código
\nEvite bibliotecas "pesadas" dentro da função. Por exemplo, em vez de importar todo o aws-sdk v3, importe apenas os clientes necessários:
// Ruim: import * as AWS from 'aws-sdk';\n// Bom:\nimport { DynamoDBClient } from '@aws-sdk/client-dynamodb';\nimport { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';\n\n2. Trabalho com Lambda Layers e dependências
\n\nLambda Layers permitem externalizar código comum e dependências (por exemplo, ORM, validadores) para fora da função. Isso acelera o deploy e reduz o tamanho de cada pacote individual.
\n\n2.1. Criação de uma camada com utilitários comuns
\nA estrutura do projeto pode ser assim:
\n\nproject/\n├── layers/\n│ └── common/\n│ └── nodejs/\n│ ├── package.json\n│ └── node_modules/\n├── functions/\n│ ├── createUser.ts\n│ └── getUser.ts\n└── serverless.yml\n\nNo serverless.yml, conectamos a camada:
layers:\n commonLibs:\n path: layers/common\n compatibleRuntimes:\n - nodejs18.x\nfunctions:\n createUser:\n handler: functions/createUser.handler\n layers:\n - { Ref: CommonLibsLambdaLayer }\n\n2.2. Tipagem para camadas
\nPara que o TypeScript "veja" os tipos da camada, crie um tsconfig.json com caminhos:
{\n "compilerOptions": {\n "paths": {\n "@common/*": ["layers/common/nodejs/*"]\n }\n }\n}\n\nAgora, na função, você pode escrever:
\nimport { validateEmail } from '@common/validators';\n\n3. Trabalho com VPC e segurança
\n\nFunções Lambda que operam dentro de uma VPC perdem o acesso à internet pública (a menos que um NAT Gateway seja configurado). Isso é crítico para conectar-se a RDS, ElastiCache ou APIs privadas.
\n\n3.1. Configuração de Lambda em VPC
\nConfiguração via serverless.yml:
provider:\n vpc:\n securityGroupIds:\n - sg-12345\n subnetIds:\n - subnet-abc\n - subnet-def\n\nfunctions:\n dbHandler:\n handler: src/db.handler\n vpc: true # herda as configurações do provider\n\n3.2. Padrão "Thin Handler" para conexões
\nLe