- Sensor Flow API
- Como Acessar a Aplicação
- System Design Atual
- Funcionalidades Implementadas
- Estrutura Modular
- Tecnologias Utilizadas
- Infraestrutura e CI/CD
- Como Executar o Projeto
- Testes de Integração
- Pensado em Escala Global
- Principais Mudanças
- Testes de Carga
Sensor Flow API é uma API para receber, processar e gerenciar registros de sensores.
A aplicação Sensor Flow está disponível na Vercel e pode ser acessada através do link abaixo:
URL da API: https://mc83rkq2t3.us-east-1.awsapprunner.com/
Também foi adicionado ao repo, um arquivo .json com as rotas da API exportadas do Insomnia, localizado em ./sensor-flow.insomnia-collection.json
obs: lembrar de preencher variáveis de ambiente no arquivo, como por exemplo api_url = https://mc83rkq2t3.us-east-1.awsapprunner.com/
Você pode utilizar um dos seguintes usuários para fazer login:
-
Usuário:
test-user
Senha:test-1234
-
Usuário:
radix
Senha:Radix2024@
- Visualizar dados de sensores.
- Consultar estatísticas e gráficos.
- Explorar dados agregados em diferentes intervalos de tempo.
A API conta com um sistema de autenticação baseado em Cognito, com suporte a cookies HTTP-only para segurança. A autenticação permite:
- Login: Autenticação de usuários utilizando
username
epassword
.- Gera um token JWT com validade de 1 hora.
- O token é armazenado em um cookie seguro
httpOnly
.
-
POST
/auth/login
- Realiza o login utilizando Basic Auth.
- Retorna uma mensagem de sucesso e configura o cookie com o token.
- O token JWT armazenado no cookie é validado utilizando o cognito.
-
GET
/auth/me
- Retorna as informações do usuário autenticado.
- Requer que o usuário esteja autenticado via JWT.
-
POST
/auth/logout
- Realiza o logout do usuário.
- Remove o cookie de autenticação.
Para que máquinas ou scripts automatizados possam interagir com a API, é necessário realizar:
Exemplo de autenticação para obter o token de acesso para máquinas:
import requests
import random
import uuid
from datetime import datetime, timedelta
# Substitua pelos valores corretos
auth_url = ''
client_id = ''
client_secret = ''
auth_payload = {
"grant_type": "client_credentials",
"client_id": client_id,
"client_secret": client_secret,
"scope": "default-m2m-resource-server-mztddy/read"
}
auth_headers = {'Content-Type': 'application/x-www-form-urlencoded'}
response = requests.post(auth_url, data=auth_payload, headers=auth_headers)
if response.status_code == 200:
token = response.json().get('access_token')
print("Token obtido com sucesso!")
else:
print(f"Erro ao obter o token: {response.status_code} {response.text}")
exit()
Também foi adicionado um exemplo de envio de dados de sensores localizado em ./send_data_example.py
-
POST
/sensor-data
- Recebe os dados de sensores no formato JSON:
{ "equipmentId": "EQ-12495", "timestamp": "2023-02-15T01:30:00.000-05:00", "value": 78.42 }
- Armazena os dados no DynamoDB com as colunas:
equipmentId
timestamp
value
registerTime
- Recebe os dados de sensores no formato JSON:
-
POST
/sensor-data/upload-csv
- Recebe um arquivo CSV contendo as colunas:
equipmentId
timestamp
value
- Armazena o arquivo CSV no AWS S3 para processamento posterior via Lambda.
- Recebe um arquivo CSV contendo as colunas:
- GET
/sensor-data/aggregated
-
Consulta dados agregados da tabela
aggregated
no DynamoDB. -
Suporta filtros dinâmicos:
24h
: últimas 24 horas48h
: últimas 48 horas1w
: última semana1m
: último mês
-
Parâmetros de consulta:
interval
: Especifica o intervalo de tempo (24h
,48h
,1w
,1m
).
-
Exemplo de requisição:
GET /sensor-data/aggregated?interval=24h
-
Exemplo de resposta:
{ "average": 78.42, "totalCount": 20, "items": [ { "equipmentId": "EQ-12495", "intervalStart": 1693468800, "totalValue": 1500.75, "sampleCount": 20 } ] }
-
Um Lambda em py é processa arquivos CSV enviados para o S3. Esta função:
- Lê o CSV utilizando pandas.
- Insere cada linha do arquivo no DynamoDB com as colunas:
equipmentId
timestamp
value
register_time
Lambda em py é acionada via dynamo stream para popular a tabela de agregados. está função
- Processa eventos do dynamo stream.
- Para cada evento:
- Extrai as informações do equipamento, timestamp e valor.
- Determina o intervalo de tempo.
- Atualiza ou cria o registro correspondente na tabela de agregados.
- A tabela de agregados tem as seguintes colunas:
partitionKey
: Valor fixo (GLOBAL
) para consultas eficientes.equipmentId
: Identificação do equipamento.intervalStart
: Timestamp do início do intervalo.totalValue
: Soma dos valores agregados.sampleCount
: Número de amostras no intervalo.
A aplicação foi projetada com uma estrutura modular utilizando o framework NestJS.
-
Auth Module:
- Implementa a autenticação via Cognito.
- Inclui estratégias JWT para validação.
-
SensorData Module:
- Gerencia o registro de dados de sensores e upload de arquivos CSV.
-
App Module:
- Ponto de entrada principal da aplicação.
- Integra os módulos de autenticação e monitoramento de saúde.
-
Config Module:
- Carrega variáveis de ambiente globais usando
@nestjs/config
.
- Carrega variáveis de ambiente globais usando
- Node.js
- NestJS
- AWS Cognito
- DynamoDB
- AWS S3
- AWS Lambda
- Python
utiliza AWS SAM para definição da infraestrutura como código e AWS CodeBuild para pipelines de CI/CD.
template.yaml
define os recursos necessários na AWS para a aplicação, incluindo S3, DynamoDB, Lambda e repositórios ECR.
A pipeline de CI/CD é acionada por commits na branch main. O processo de build segue os seguintes passos:
-
Build dos Lambdas:
- Utiliza o arquivo
buildspec_lambda.yml
para construir as funções Lambda.
- Utiliza o arquivo
-
Deploy da Infraestrutura:
- Utiliza o
template.yaml
para deployar recursos como Lambdas, S3, DynamoDB e repositórios ECR.
- Utiliza o
-
Build da API NestJS:
- Utiliza o arquivo
buildspec-nest.yml
para construir a aplicação NestJS. - A imagem resultante é enviada para o repositório ECR criado na etapa anterior.
- Utiliza o arquivo
-
Configuração do App Runner:
- É necessário criar um App Runner e registrar a imagem do ECR.
- O App Runner é configurado para atualizar automaticamente sempre que uma nova imagem é enviada ao repositório ECR.
- buildspec_lambda.yml: Para construir e empacotar as funções Lambda.
- buildspec-nest.yml: Para construir e publicar a aplicação NestJS no Amazon ECR.
-
Clone o repositório:
git clone https://github.com/seu-usuario/sensor-flow.git cd sensor-flow
-
Instale as dependências:
npm install
-
Configure as variáveis de ambiente no arquivo
.env
:AWS_REGION=seu-regiao COGNITO_CLIENT_ID=seu-client-id COGNITO_CLIENT_SECRET=seu-client-secret COGNITO_AUTH_URI=seu-auth-uri DYNAMODB_TABLE_NAME=sensor-data-table DYNAMODB_AGGREGATE_TABLE_NAME=aggregated-data-table S3_BUCKET_NAME=sensor-data-bucket
-
Execute a aplicação:
npm run start
O projeto inclui testes de integração. Para executar os testes, siga os passos abaixo:
Execute os testes:
npm run test:e2e
-
Health module integration tests
- Verifica se o endpoint /
-
Auth module integration tests
- Testa o fluxo de autenticação:
- Login bem-sucedido e recebimento do cookie de autenticação.
- Falha no login com credenciais incorretas.
- Logout e remoção do cookie de autenticação.
- Acesso negado a rotas protegidas após logout.
- Testa o fluxo de autenticação:
-
Sensor aggregated data module integration tests
- Testa a recuperação de dados agregados com diferentes intervalos de tempo (
24h
,48h
,1w
,1m
) e valida respostas de sucesso.
- Testa a recuperação de dados agregados com diferentes intervalos de tempo (
-
Sensor data module integration tests
- Testa o registro de dados de sensores:
- Criação bem-sucedida de dados de sensores.
- Falha ao criar dados de sensores com payload inválido.
- Testa o upload de arquivos CSV:
- Upload bem-sucedido de um arquivo CSV válido.
- Rejeição de uploads sem arquivos.
- Rejeição de uploads com arquivos não CSV.
- Testa o registro de dados de sensores:
- Alteração do App Runner para ECS Fargate.
- Proporciona uma escalabilidade mais eficiente e com maior controle.
- Integrando com ALB ao ECS Fargate permite distribuir as requisições de maneira eficiente.
- Adição de um Application Load Balancer para distribuir o tráfego entre os containers da aplicação
- Oferece suporte a roteamento inteligente e balanceamento de carga eficiente.
- Alteração no método de upload de arquivos para utilizar pre-signed URLs
- Aplicação não precise lidar com o upload de arquivos, apenas com a geração de URLs para que os usuários possam fazer o upload diretamente para o S3, desafogando a aplicação
- Deploy da aplicação em múltiplas regiões para melhorar disponibilidade e latência.
- Melhora a disponibilidade e a latência em diferentes regiões
- Adição de um cache Redis para armazenar dados temporários e acelerar o acesso a dados frequentemente acessados.
- Comparado ao nestjs-cache, o Redis oferece mais flexibilidade e escalabilidade.
Como executar Locust:
locust -f locust/locustfile.py
em seguida, acesse http://localhost:8089
para configurar e iniciar os testes de carga.
Resultados dos testes de carga utilizando o Locust com diferentes volumes de requisições:
- Baixar relatório Para visualizar, faça o download do arquivo descompacte e abra os arquivos html em um navegador.