IT & Engineering

Como o app Node.js Cloud Monitoring usa a API do Mailgun para automatizar o fluxo de trabalho de e-mail

Esta postagem foi escrita por Dan Di Spaltro, diretor de produto do Rackspace Cloud Monitoring. O Cloud Monitoring permite que você monitore qualquer servidor em qualquer data center para que possa sempre ter certeza de que a infraestrutura do seu aplicativo está funcionando perfeitamente. Antes de liderar a equipe de engenharia do Cloud Monitoring, Dan foi cofundador da Cloudkick, uma startup da Y-Combinator focada no monitoramento de infraestrutura em nuvem que foi adquirida pela Rackspace em 2010.
Imagem para Como o app Node.js Cloud Monitoring usa a API do Mailgun para automatizar o fluxo de trabalho de e-mail

Esta postagem foi escrita por Dan Di Spaltro, diretor de produto da Rackspace Cloud Monitoring. O Cloud Monitoring permite que você monitore qualquer servidor em qualquer data center para que possa sempre ter certeza de que a infraestrutura do seu aplicativo está funcionando perfeitamente. Antes de liderar a equipe de engenharia do Cloud Monitoring, Dan foi cofundador da Cloudkick, uma startup da Y-Combinator focada no monitoramento de infraestrutura em nuvem que foi adquirida pela Rackspace em 2010. 

A equipe de engenharia da Rackspace está sempre em busca de maneiras de usar os produtos da Rackspace nas soluções que criamos para clientes. Acreditamos que, quando usamos nossos próprios produtos, criamos softwares melhores para nossos clientes porque podemos fornecer feedback à equipe que trabalha na sala ao lado. Durante a aquisição do Mailgun pela Rackspace, tivemos uma oportunidade única de testar o mais novo conjunto de serviços da Rackspace no nosso produto Cloud Monitoring. Grande parte do que o Cloud Monitoring faz quando ocorre um erro é enviar um e-mail para o cliente. Esses e-mails podem ser acionados quando o site monitorado atinge o tempo limite, responde com um erro 404 ou quando alguma outra condição definida pelo usuário em sua Alarm Language é atendida. Quando investigamos o Mailgun, nosso objetivo era habilitar notificações de e-mail de forma confiável para nossos clientes, e não dominar os detalhes de criação, entrega e análises de e-mail, três componentes essenciais da automação de e-mail em nossa escala. Quando testamos o Mailgun, ficamos muito impressionados. Obtivemos os benefícios que esperávamos e até alguns que não imaginávamos. Por exemplo:

  • Devoluções sensatas – o Mailgun oferece uma maneira racional baseada em API para lidar com devoluções que acontecem frequentemente por vários motivos diferentes.
  • Análises e tags – testamos constantemente cenários de falha em nosso ambiente de produção, por isso precisávamos de uma forma de isolar determinadas contas que marcamos como “especiais”. O Mailgun pode segmentar todos os relatórios com base em tags, o que facilita os testes.
  • Responsabilidade – apenas enviar um e-mail não é suficiente para nós. Os logs do Mailgun fornecem uma visão de ponta a ponta de exatamente o que aconteceu com cada e-mail.

Antes de analisar como implementamos e lançamos o Mailgun, vejamos a arquitetura do Cloud Monitoring

Pipeline do Cloud Monitoring

O sistema Rackspace Cloud Monitoring é dividido em um pipeline de diferentes serviços; apenas para relembrar, vejamos uma visão panorâmica da arquitetura.

chart

Cada etapa representa um ou mais serviços distribuídos, conectados por um fluxo de dados. Usamos o software Scribe do Facebook para distribuição ponto a ponto, roteamento e armazenamento em buffer. Com esse fluxo de dados, podemos fatiar, dividir e distribuir os dados para qualquer canto da infraestrutura que quisermos. A facilidade de experimentação com o fluxo de dados é fundamental para nossa velocidade. Ele nos permite enviar dados para qualquer lugar e é uma parte essencial do design que dá suporte à nossa alta disponibilidade, bem como à aceleração e ao desenvolvimento do produto (curiosidade: é por isso que o produto tem o codinome de ELE.).

Preparação para o teste

Para um sistema de produção, a mudança em grande escala nunca é uma boa ideia, então decidimos adotar uma abordagem diferente. Primeiro, implementamos o Mailgun gradualmente nas contas que usamos para nossos testes. Isso nos permitiu ir além das microvalidações e validações de testes de unidade para nos familiarizarmos com o sistema. Graças ao fácil suporte para HTTP no Node.js, conseguimos realizar essa integração rapidamente.

Simulação da API do Mailgun

Toda vez que adicionamos uma dependência externa, tentamos fazer o mock da API, se possível. Fazer o mock de uma API externa pode ser muito simples ou muito elaborado, mas ainda assim importante. Nosso objetivo não é adicionar trabalho extra para a equipe de desenvolvimento, mas manter a confiança em nossas interações com um serviço externo e como ele deve funcionar. Hoje em dia, a maioria das APIs tem controle de versão, por isso grandes mudanças vêm com uma atualização de versão. Isso nos permite fazer o mock de APIs de forma rápida e confiável para criar testes de ponta a ponta mais elaborados em um ambiente controlado. Depois de determinar como queríamos lançar o teste em nossa conta de testes, criamos nossa própria API do Mailgun, o que nos permitiu nos familiarizar com a nova integração. Esse processo foi muito simples. A API do Mailgun oferecida por todas as operações de saída e análises foi simples e direta de implementar. Somente depois de fazer o mock é que percebemos que havia um modo de teste na sandbox para enviar e-mails, mas, de qualquer forma, foi uma experiência de aprendizado valiosa.

Substituição cirúrgica

Com as preparações para o teste concluídas, começamos a implementar e monitorar o desempenho dos e-mails para ganhar a confiança de que o Mailgun era algo que poderíamos lançar de forma mais ampla para nossos usuários. No aplicativo Cloud Monitoring, o componente para garantir a entrega de um alerta é um software complexo apropriadamente chamado de messenger. Ele realiza várias tarefas para aumentar a confiabilidade das nossas notificações de e-mail. Internamente, o messenger é um pipeline de execução em estágios. Ele tem as seguintes etapas:

  • Receber a mensagem
  • Bloquear o átomo da mensagem
  • Realizar pesquisas de conta/entidade/verificação/alarme
  • Encontrar o plano de notificação
  • Entregar alertas
  • Criar e-mail
  • Entregar
  • Rastrear

Durante o teste, adicionamos código para analisar a conta especial durante a etapa de entregar alertas e começar a rotear mensagens para o Mailgun. Esse processo foi simples porque envolveu pouco código. Veja como é um snippet:

                                

                                    if (tenantId === 'XXX') {rn    emailUtil.sendMailgunEmail(address, subject, body, { headers: headers }, function (err, res) {rn        var delta = (Date.now() - startTime);rnrn        accessLog.logAccess(ctx, 'mailgun', misc.getUnixTimestamp(), delta, err);rnrn        if (err) {rn            log.error('error performing email notification', { ctx: ctx, err: err });rn            callback(err);rn            return;rn        }rnrn        callback(null, 'Email successfully sent', body);rn    });rn} else {rn    // ...rn}
                                
                            

O que está acontecendo acima? Primeiro, chamamos a função sendMailgunEmail para entregar o e-mail de notificação de monitoramento. Na busca de medir TUDO, também medimos o tempo que leva para usar a API do Mailgun. E há uma série de novas tentativas que envolve esse código com uma opção de fallback, uma das práticas recomendadas ao depender de qualquer sistema de terceiros no seu aplicativo. Quer ver como a função sendMailgunEmail é simples?

                                

                                    exports.sendMailGunEmail = function(address, subject, body, options, callback) {rn    options = options || {};rn    options.headers = options.headers || {};rn    options.apiUrl = options.apiUrl || settings.MAILGUN_API_URL;rn    options.domain = options.domain || settings.MAILGUN_DOMAIN;rn    options.apiKey = options.apiKey || settings.MAILGUN_API_KEY;rn    options.fromAddress = options.fromAddress || settings.MAILGUN_FROM_ADDRESS;rn    options.testMode = options.testMode || settings.MAILGUN_TEST_MODE;rnrn    var url = options.apiUrl + options.domain + '/messages',rn        bodyObj, k, httpOptions;rnrn    httpOptions = { // 1) set up some defaultsrn        'expected_status_codes': [200],rn        'return_response': true,rn        'parse_json': true,rn        'username': 'api',rn        'password': options.apiKey,rn        'headers': { 'Content-Type': 'application/x-www-form-urlencoded' }rn    };rnrn    bodyObj = {rn        'to': address,rn        'subject': subject,rn        'from': options.fromAddressrn    };rnrn    if (options.isHTML) { // 2) switch based on the content type we want to sendrn        bodyObj.html = body;rn    } else {rn        bodyObj.text = body;rn    }rnrn    for (k in options.headers) { // 3) merge in the headers so we can provide id’s as headers in the emailsrn        if (options.headers.hasOwnProperty(k)) {rn            bodyObj['h:' + k] = options.headers[k];rn        }rn    }rnrn    if (options.testMode) { // 4) enable sandbox testingrn        bodyObj['o:testmode'] = true;rn    }rnrn    if (options.tags) { rn        // 5) set some tags to automatically pivot analytics for visibility.rn        // (we view reporting in the Mailgun control panel but data is also available via API or webhook)rn        bodyObj['o:tag'] = options.tags;rn    }rnrn    body = querystring.stringify(bodyObj);rn    request(url, 'POST', body, httpOptions, callback);rn};
                                
                            

1) A função request abstrai um pouco a forma de lidar com solicitações HTTP complexas e o tratamento de códigos de resposta, de modo que os códigos de response esperados são usados para isso.

2) Lide facilmente com o envio de HTML, que geralmente é um problema.

3) Mescle cabeçalhos, permitindo uma maneira fácil de enriquecer e-mails. Esses cabeçalhos nos permitem criar e-mails personalizados para cada usuário com detalhes sobre o seu alerta, como alarmId, checkId e tenantId. Você pode passar quase qualquer coisa para personalizar seus e-mails nesses cabeçalhos, que normalmente apenas poluiriam o corpo do e-mail.

4) Inverta facilmente um bit para enviar e-mails de teste.

5) As tags definidas pelo usuário permitem o rastreamento e a segmentação analítica usados em nossos cenários de testes de produção.

Veja como foi fácil. Automatizamos totalmente a criação, a entrega e o rastreamento de e-mails usando o Mailgun, algo que é difícil com uma configuração tradicional no estilo “faça você mesmo”.

Resumo

Mudar para uma oferta hospedada é uma grande decisão para qualquer aplicativo, especialmente em algo tão essencial quanto notificações de e-mail. Com um plano de teste rigoroso e um suporte excelente da equipe do Mailgun em tudo, desde a configuração de registros DKIM até a integração com a API, conseguimos transferir com sucesso todas as nossas notificações de e-mail do Cloud Monitoring para o Mailgun. Um bônus adicional, a equipe do Mailgun trabalha bem do meu lado ;). PS Estamos contratando!