Como testar uma origem com Functions
Testar novo software com dados sintéticos frequentemente perde padrões de uso do mundo real. Functions executando no Firewall podem espelhar tráfego de produção para uma origem de teste, permitindo validar o comportamento do novo software com requisições reais de usuários—sem afetar a experiência do usuário.
Como funciona
Functions no listener do Firewall podem executar tarefas sem impactar as requisições dos usuários. Quando uma requisição chega ao Firewall, a função cria uma requisição duplicada e a envia para sua origem de teste, enquanto a requisição original continua para sua origem de produção. Isso acontece de forma assíncrona, sem adicionar latência às requisições dos usuários.
Benefícios principais:
- Validação com tráfego real: Teste com dados reais de usuários, incluindo casos de borda que testes sintéticos perdem
- Zero impacto ao usuário: Requisições completam normalmente enquanto dados de teste são coletados
- Teste em escala de produção: Verifique se sua nova origem suporta a carga de produção
- Monitoramento configurável: Registre respostas, erros e métricas de latência
Pré-requisitos
Antes de começar, certifique-se de ter:
- Uma application com tráfego de produção
- Um domínio associado à sua aplicação
- Uma origem de teste (seu novo software) acessível via HTTPS
- Um Firewall associado ao seu domínio
Criando a função de espelhamento de tráfego
Passo 1: Criar uma nova função
- Acesse o Azion Console > Functions.
- Clique em + Function.
- Nomeie sua função (ex:
Traffic Mirroring). - Na aba Code, adicione o seguinte código:
const TEST_DOMAIN = "www.your-test-origin.com";
async function firewallHandler(event) { const originalUrl = new URL(event.request.url); const testUrl = `${originalUrl.protocol}//${TEST_DOMAIN}${originalUrl.pathname}${originalUrl.search}`;
let fetchOptions = { method: event.request.method, headers: Object.fromEntries(event.request.headers) };
if (event.request.body) { fetchOptions["body"] = await event.request.text(); }
event.waitUntil(fetch(testUrl, fetchOptions)); event.continue();}
addEventListener("firewall", (event) => event.waitUntil(firewallHandler(event)));- Substitua
www.your-test-origin.compelo domínio da sua origem de teste. - Clique em Save.
Passo 2: Configurar a função no Firewall
- Acesse o Azion Console > Firewall.
- Selecione o firewall associado ao seu domínio.
- Habilite o módulo Functions se ainda não estiver habilitado.
- Vá para a aba Functions Instances.
- Clique em + Function Instance.
- Nomeie sua instância (ex:
Traffic Mirroring Instance). - Selecione a função
Traffic Mirroring. - Clique em Save.
Passo 3: Criar uma regra para disparar a função
- No mesmo firewall, vá para a aba Rules Engine.
- Clique em + Rule.
- Nomeie sua regra (ex:
Mirror Traffic to Test Origin). - Em Criteria, configure quando espelhar o tráfego:
- If
${uri}matches regex.*(espelha todas as requisições) - Ou especifique caminhos: If
${uri}starts with/api(espelha apenas requisições de API)
- If
- Em Behaviors, selecione Run Function.
- Escolha a
Traffic Mirroring Instance. - Clique em Save.
Aguarde alguns minutos para a propagação. Sua função agora espelha o tráfego de produção para sua origem de teste.
Adicionando monitoramento com Real-Time Events
Para entender como sua origem de teste responde, adicione logging que aparece no Real-Time Events.
Passo 4: Atualizar a função com logging
Substitua o código da sua função por:
const TEST_DOMAIN = "www.your-test-origin.com";
async function firewallHandler(event) { try { const originalUrl = new URL(event.request.url); const testUrl = `${originalUrl.protocol}//${TEST_DOMAIN}${originalUrl.pathname}${originalUrl.search}`;
let fetchOptions = { method: event.request.method, headers: Object.fromEntries(event.request.headers), signal: AbortSignal.timeout(5000) // Timeout menor para fases de diagnóstico; aumente se sua origem de teste for lenta. A versão reutilizável no Passo 6 usa 10000 ms como padrão. };
if (event.request.body) { fetchOptions["body"] = await event.request.text(); }
const startTime = Date.now(); const testOriginResponse = await fetch(testUrl, fetchOptions); const responseTime = (Date.now() - startTime) / 1000;
event.console.log(`[${testOriginResponse.status}, ${responseTime}s]`);
if (testOriginResponse.status > 399) { // Nota: esta estrutura de log estende os campos canônicos da // referência fonte com request_path e response_time // para contexto adicional de observabilidade. event.console.warn(JSON.stringify({ request_method: event.request.method, request_body: fetchOptions["body"], request_headers: fetchOptions["headers"], response_body: await testOriginResponse.text(), response_status: testOriginResponse.status, request_path: originalUrl.pathname, // campo estendido response_time: responseTime // campo estendido })); } } catch (err) { if (err.name === "TimeoutError") { event.console.warn("Test origin timeout"); } else { event.console.warn(`Error: ${err.message}`); } }
// event.continue() está FORA do try/catch intencionalmente. // Isso garante que a requisição do usuário sempre prossiga para a origem de produção, // independentemente de erros na comunicação com a origem de teste. event.continue();}
addEventListener("firewall", (event) => event.waitUntil(firewallHandler(event)));Esta versão atualizada:
- Registra status de resposta e tempo para cada requisição
- Registra informações detalhadas para respostas de erro (4xx e 5xx)
- Implementa um timeout de 5 segundos para prevenir requisições de longa duração
- Trata timeouts e outros erros de forma elegante
Passo 5: Visualizar logs no Real-Time Events
- Acesse o Azion Console > Real-Time Events.
- Selecione Functions nas opções de filtro.
- Filtre pelo nome da sua função ou firewall.
- Observe os logs aparecendo conforme as requisições são processadas.
Você verá entradas como:
[200, 0.142s]— Respostas bem-sucedidas com latência- Logs de aviso com detalhes da requisição para respostas de erro
- Avisos de timeout se sua origem de teste for lenta
Tornando a função reutilizável
Para múltiplos cenários de teste, use variáveis de ambiente e JSON Args em vez de valores fixos no código.
Passo 6: Criar uma função reutilizável
Atualize o código da sua função:
async function firewallHandler(event) { try { const testDomain = event.args.url || Azion.env.get("TEST_URL") || "www.default-test.com"; const testTimeout = event.args.timeout || Azion.env.get("TEST_TIMEOUT") || 10000;
const originalUrl = new URL(event.request.url); const testUrl = `${originalUrl.protocol}//${testDomain}${originalUrl.pathname}${originalUrl.search}`;
let fetchOptions = { method: event.request.method, headers: Object.fromEntries(event.request.headers), signal: AbortSignal.timeout(testTimeout) };
if (event.request.body) { fetchOptions["body"] = await event.request.text(); }
const startTime = Date.now(); const testOriginResponse = await fetch(testUrl, fetchOptions); const responseTime = (Date.now() - startTime) / 1000;
event.console.log(`[${testOriginResponse.status}, ${responseTime}s]`);
if (testOriginResponse.status > 399) { // Nota: esta estrutura de log estende os campos canônicos da // referência fonte com request_path e response_time // para contexto adicional de observabilidade. event.console.warn(JSON.stringify({ request_method: event.request.method, request_body: fetchOptions["body"], request_headers: fetchOptions["headers"], response_body: await testOriginResponse.text(), response_status: testOriginResponse.status, request_path: originalUrl.pathname, // campo estendido response_time: responseTime // campo estendido })); } } catch (err) { if (err.name === "TimeoutError") { event.console.warn("Test origin timeout"); } else { event.console.warn(`Error: ${err.message}`); } }
// event.continue() está FORA do try/catch intencionalmente. // Isso garante que a requisição do usuário sempre prossiga para a origem de produção, // independentemente de erros na comunicação com a origem de teste. event.continue();}
addEventListener("firewall", (event) => event.waitUntil(firewallHandler(event)));Agora você pode configurar a função através de:
- JSON Args: Adicione
{"url": "www.test-origin.com", "timeout": 3000}na instância da função - Variáveis de ambiente: Defina
TEST_URLeTEST_TIMEOUTno ambiente da sua função
Isso permite criar múltiplas instâncias da função com diferentes origens de teste sem modificar o código.
Analisando os resultados do teste
Após executar o espelhamento de tráfego, analise o comportamento da sua origem de teste:
- Tempos de resposta: Compare a latência entre as origens de produção e teste
- Taxas de erro: Verifique respostas 4xx e 5xx nos logs do Real-Time Events
- Frequência de timeout: Monitore com que frequência as requisições excedem seu limite de timeout
- Padrões de requisição: Verifique se sua origem de teste trata todos os tipos de requisição (GET, POST, PUT, DELETE)
Quando sua origem de teste tratar o tráfego de produção com sucesso, com latência e taxas de erro aceitáveis, ela está pronta para implantação em produção.