Node.js: serious business
-
Upload
pedro-franceschi -
Category
Technology
-
view
5.142 -
download
4
description
Transcript of Node.js: serious business
![Page 2: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/2.jpg)
• O problema
• Por que e quando usar Node.js?
• Problemas de Node.js
• Node.js “the right way”
• Repensando a infraestrutura
• Deployment (Continuous Integration) e monitoramento
• Conclusões…
Assuntos
![Page 3: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/3.jpg)
O problema
![Page 4: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/4.jpg)
“Montar um gateway de pagamentos amigável para desenvolvedores e
empreendedores”
![Page 5: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/5.jpg)
“A forma mais simples de receber pagamentos online”
![Page 6: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/6.jpg)
API RESTful
Dashboard Angular.js
RubyNode.js
Python Java
.NET
PHPC#
![Page 7: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/7.jpg)
• Simplicidade: RESTful + JSON
• Ambiente de testes isolado e decente
• Segurança sem comprometer simplicidade
• Uptime de 99,9%
• Escalabilidade
Premissas da API
![Page 8: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/8.jpg)
Por que Node.js?
![Page 9: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/9.jpg)
Antes...
![Page 10: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/10.jpg)
![Page 11: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/11.jpg)
Por que Node.js?
Request de transação
API RESTful
Sistema antifraude
fraude
legítimaAdquirente (Cielo, RedeCard, etc)
10.000 ms
3.000
ms
sucesso/erro
erro
![Page 12: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/12.jpg)
Por que Node.js? (no nosso caso)
• Requests externos demorados (>1.000ms)
• I/O intenso em banco de dados
• Totalmente assíncrono, single thread e event-based
• Pouco processamento (sem blocking de CPU)
![Page 13: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/13.jpg)
Por que Node.js? (no nosso caso)
“Mas é só usar threads em qualquer linguagem!..”
Não.
![Page 14: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/14.jpg)
Por que Node.js? (no nosso caso)
1.000 requests por segundo com conexão a uma API externa + I/O no DB = 1.000 threads por segundo
… se cada request leva em média 10 segundos …
Em 9 segundos, teremos 9.000 threads
Isso escala? :P :P :P
![Page 15: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/15.jpg)
Por que Node.js? (no nosso caso)
Agora, em Node.js…
![Page 16: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/16.jpg)
Por que Node.js? (no nosso caso)
1.000 requests por segundo com conexão a uma API externa + I/O no DB = 1 thread
… se cada request leva em média 10 segundos …
Em 9 segundos, teremos 1 thread
Isso escala? Sim.#eventloopFTW
![Page 17: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/17.jpg)
I/O síncrona
Aplicação
Sistema operacional
I/Oretorno
I/O bloqueante (aplicação travada)
I/Oretorno
I/O bloqueante (aplicação travada)
I/Oretorno
I/O bloqueante (aplicação travada)
![Page 18: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/18.jpg)
I/O “assíncrona” com threads
Aplicação
Sistema operacional
I/O
Thread
callback
I/O bloqueante (thread travada)
I/O
Thread
callback
I/O bloqueante (thread travada)
I/O
Thread
callback
I/O bloqueante (thread travada)
![Page 19: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/19.jpg)
O segredo do Node.js
JavaScript (event loop)
V8
libuv
Sistema operacional……………………………………
operações assíncronas em nível de OS
…………………………………………………………………………
I/Ocallback
I/OI/O
callbackcallback
![Page 20: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/20.jpg)
Node.js escala em I/O bloqueante, não em utilização de CPU
(threads são boas em processamento paralelo)
![Page 21: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/21.jpg)
Se I/O bloqueante não for um problema, Node.js não tem tantas vantagens.
![Page 22: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/22.jpg)
![Page 23: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/23.jpg)
Problemas de Node.js
![Page 24: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/24.jpg)
Código assíncrono (race conditions, callback hell, testes assíncronos, etc)
db.query("SELECT a FROM users WHERE ...;", function (err, result1) { db.query("SELECT b FROM users WHERE ...;", function (err, result2) { db.query("SELECT c FROM users WHERE ...;", function (err, result3) { db.query("SELECT d FROM users WHERE ...;", function (err, result4) { db.query("SELECT e FROM users WHERE ...;", function (err, result5) { console.log("Finished."); }); }); }); }); });
Um ótimo exemplo do que não fazer: callback hell.
Problemas de Node.js
![Page 25: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/25.jpg)
Problemas de Javascript: bizarrices e facilidade em não seguir padrões e orientação a objetos.
> 0.1+0.2 0.30000000000000004 !> typeof NaN 'number' !> NaN === NaN false
Cortesia do wtfjs.com
Problemas de Node.js
![Page 26: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/26.jpg)
Exceptions não tratadas matam o processo.var name = “Pedro Franceschi"; !console.log("Tamanho do primeiro nome: " + name.split(" ")[0].length); console.log("Tamanho do segundo nome: " + name.split(" ")[1].length);
Problemas de Node.js
$ node test.js Tamanho do primeiro nome: 5 Tamanho do segundo nome: 10
![Page 27: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/27.jpg)
Exceptions não tratadas matam o processo.var name = “Pedro"; !console.log("Tamanho do primeiro nome: " + name.split(" ")[0].length); console.log("Tamanho do segundo nome: " + name.split(" ")[1].length);
Problemas de Node.js
$ node test.js Tamanho do primeiro nome: 5 !/private/tmp/test.js:4 console.log("Tamanho do segundo nome: " + name.split(" ")[1].length); ^ TypeError: Cannot read property 'length' of undefined at Object.<anonymous> (/private/tmp/test.js:4:61) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Function.Module.runMain (module.js:497:10) at startup (node.js:119:16) at node.js:901:3
![Page 28: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/28.jpg)
Problemas de Node.js
• Single thread (escalar horizontalmente e verticalmente com múltiplas instâncias)
• Leaks de memória difíceis de detectar devido a código mal feito (variáveis globalizadas, closures, etc)
• Programadores front-end mexendo em back-end (“é tudo Javascript!!”)
• Existe a 4 anos, porém ainda é beta (v0.10.22)
![Page 29: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/29.jpg)
Node.js “the right way”
![Page 30: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/30.jpg)
Modules
Node.js “the right way”
var PI = Math.PI; !exports.area = function (r) { return PI * r * r; }; !exports.circumference = function (r) { return 2 * PI * r; };
circle.js
var circle = require('./circle.js'); !console.log( 'The area of a circle of radius 4 is ' + circle.area(4));
main.js
![Page 31: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/31.jpg)
Evitar callback hells com async (https://github.com/caolan/async)
Node.js “the right way”
Não tente fazer isso em casa
db.query("SELECT a FROM users WHERE ...;", function (err, result1) { db.query("SELECT b FROM users WHERE ...;", function (err, result2) { db.query("SELECT c FROM users WHERE ...;", function (err, result3) { db.query("SELECT d FROM users WHERE ...;", function (err, result4) { db.query("SELECT e FROM users WHERE ...;", function (err, result5) { console.log("Finished."); }); }); }); }); });
![Page 32: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/32.jpg)
Node.js “the right way”
async.parallel({ result1: function(callback) { db.query("SELECT a FROM users WHERE ...;", function(err, result1){ callback(err, result1); }); }, result2: function(callback) { db.query("SELECT b FROM users WHERE ...;", function(err, result2){ callback(err, result2); }); }, result3: function(callback) { db.query("SELECT c FROM users WHERE ...;", function(err, result3){ callback(err, result3); }); } }, function(err, results){ console.log("Finished."); })
Assim é bem melhor :)
Evitar callback hells com async (https://github.com/caolan/async)
![Page 33: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/33.jpg)
Node.js “the right way”
describe('Array', function(){ describe('#indexOf()', function(){ it('should return -1 when the value is not present', function(){ [1,2,3].indexOf(5).should.equal(-1); }) }) ! describe(‘#indexOf() after one second', function(){ before(function(done){ setTimeout(function(){ done(); }, 1000); }); ! it('should return -1 when the value is not present', function(){ [1,2,3].indexOf(5).should.equal(-1); }) }) });
Testes (JavaScript quebra) (https://github.com/visionmedia/mocha e https://github.com/visionmedia/should.js/)
![Page 34: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/34.jpg)
Node.js “the right way”
• Seguir e manter um code style (dica: Google JavaScript Style Guide)
• Tratamento de erros consistente (processos morrem)
![Page 35: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/35.jpg)
Node.js “the right way” utils
• Express.js: lightweight HTTP framework
• Sequelize: ORM de MySQL, PostgreSQL, sqlite3, etc.
• Mongoose: ORM de MongoDB
• Commander: wrapper de command line
• Vim: melhor editor de texto :P
![Page 36: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/36.jpg)
“Inovação” em padrões de código não é inovação.
(99,9% das vezes)
![Page 37: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/37.jpg)
“Follow the patterns”
![Page 38: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/38.jpg)
Repensando a infraestrutura
![Page 39: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/39.jpg)
Use o melhor de cada banco de dados.
![Page 40: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/40.jpg)
Infraestrutura do Pagar.me
Router
api.pagar.me
Servidor da API (Node.js)
ElasticSearchElasticSearch
MySQL (transações e dados relacionais)
MySQL (transações e dados relacionais)
MongoDB (dados de clientes e não relacionais)
Ambiente de testes (sandbox dos clientes)
Ambiente de produção
Servidor da API (Node.js)
![Page 41: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/41.jpg)
Por que tantos bancos?
• Separar dados de teste (sandbox dos clientes) dos dados de produção
• MySQL: dados relacionais (transações, assinaturas, planos, cartões, etc.)
• MongoDB: dados não-relacionais (informações do cliente, usuários de uma conta, etc.)
• ElasticSearch: indexação/buscas ultra-rápidas (expondo uma engine de buscas poderosa para os clientes)
• Não há porque se prender a uma tecnologia quando cada uma delas resolve uma parte do seu problema
![Page 42: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/42.jpg)
Um parênteses...
![Page 43: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/43.jpg)
ElasticSearch
• “Open Source Distributed Real Time Search & Analytics”
• Construído em Java em cima do Apache Lucene (engine robusta de busca e indexação em Java)
• API RESTful (POST para inserir (indexar) dados num “model”, GET para buscá-los)
• Just works and scales (sem instalação, basta iniciar o servidor; suporte a clusters out of the box)
• Nosso uso: indexar/buscar responses (incluindo metadata e nested objects) de models do MySQL
![Page 44: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/44.jpg)
ElasticSearch
Transaction Customer Address Phone
amount name customer_id customer_id
payment_method email street ddd
card_last_digits document_number neighborhood number
customer_id document_type id id
address_id id
phone_id
3 joins para montar o objeto de resposta
{ "object": "transaction", "status": "paid", "date_created": "2013-11-21T02:27:10.000Z", "amount": 1000, "installments": 1, "id": 35, "card_holder_name": "PEDRO FRANCESCHI", "card_last_digits": "5592", "card_brand": "visa", "payment_method": "credit_card", "antifraud_score": null, "subscription_id": null, "customer": { "object": "customer", "document_number": "12388451908", "document_type": "cpf", "name": "Pedro Franceschi", "email": null, "born_at": null, "date_created": "2013-11-11T05:24:52.000Z", "id": 1 }, "address": { "object": "address", "street": "Av. Brigadeiro Faria Lima 2941", "street_number": "2941", "neighborhood": “Itaim Bibi", "city": "São Paulo", "state": "SP", "zipcode": "01452000", "country": "Brasil", "id": 1 }, "phone": { "object": "phone", "ddi": "55", "ddd": "21", "number": "88888888", "id": 1 }, "metadata": null }
![Page 45: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/45.jpg)
ElasticSearch $ curl -X POST http://0.0.0.0:9200/pagarme/transactions/35 -d ‘ { "object": "transaction", "status": "paid", "date_created": "2013-11-21T02:27:10.000Z", "amount": 1000, "installments": 1, "id": 35, "card_holder_name": "PEDRO FRANCESCHI", "card_last_digits": "5592", "card_brand": "visa", "payment_method": "credit_card", "antifraud_score": null, "subscription_id": null, "customer": { "object": "customer", "document_number": "12388451908", "document_type": "cpf", "name": "Pedro Franceschi", "email": null, "born_at": null, "date_created": "2013-11-11T05:24:52.000Z", "id": 1 }, "address": { "object": "address", "street": "Av. Brigadeiro Faria Lima 2941", "street_number": "2941", "neighborhood": “Itaim Bibi", "city": "São Paulo", "state": "SP", "zipcode": "01452000", "country": "Brasil", "id": 1 }, "phone": { "object": "phone", "ddi": "55", "ddd": "21", "number": "88888888", "id": 1 }, "metadata": null }’
Transaction Customer Address Phone
amount name customer_id customer_id
payment_method email street ddd
card_last_digits document_number neighborhood number
customer_id document_type id id
address_id id
phone_id
ElasticSearch indexa o JSON já montado pelo seu id em um índice (model) específico.
![Page 46: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/46.jpg)
ElasticSearch$ curl -X GET http://0.0.0.0:9200/pagarme/transactions/35 { "_index": "pagarme", "_type": "transaction", "_id": "35", "_version": 2, "exists": true, "_source": { "object": "transaction", "status": "paid", "date_created": "2013-11-21T02:27:10.000Z", "amount": 1000, "installments": 1, "id": 35, "card_holder_name": “PEDRO FRANCESCHI", "card_last_digits": "5592", "card_brand": "visa", "payment_method": "credit_card", "antifraud_score": null, "subscription_id": null, "customer": { "object": "customer", "document_number": "12388451908", "document_type": "cpf", "name": "Pedro Franceschi", "email": null, "born_at": null, "date_created": "2013-11-11T05:24:52.000Z", "id": 1 }, "address": { "object": "address", "street": "Av. Brigadeiro Faria Lima 2941", "street_number": "2941", "neighborhood": “Itaim Bibi", "city": "São Paulo", "state": "SP", "zipcode": "01452000", "country": "Brasil", "id": 1 }, "phone": { "object": "phone", "ddi": "55", "ddd": "21", "number": "88888888", "id": 1 }, "metadata": null, } }
Transaction Customer Address Phone
amount name customer_id customer_id
payment_method email street ddd
card_last_digits document_number neighborhood number
customer_id document_type id id
address_id id
phone_id
Para retornar o objeto, basta realizar um GET pelo seu id (o objeto é retornado dentro de “_source”)
![Page 47: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/47.jpg)
ElasticSearch (buscando…)
$ curl -X GET ‘http://localhost:9200/pagarme/transaction/_search’ -d ' { "query": { "bool": { "must": [ { "text": { "payment_method": "credit_card" } }, { "text": { "address.zipcode": "01452000" } }, { "range": { "amount": { "gt": 1000 } } } ] } } }'
![Page 48: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/48.jpg)
ElasticSearch
• NÃO é um banco de dados. É um indexador.
• Evita I/O no DB (salva JSONs construídos a partir das queries no DB)
• Permite buscas em cima dos próprios objetos que são retornados para os clientes (padroniza o que é exposto nos responses independente da estrutura do DB)
• Dashboard em tempo real a partir das indexações
• Dica: crie um script para indexar seu DB (indexar em tempo real funciona mas pode quebrar)
![Page 49: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/49.jpg)
Deployment
![Page 50: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/50.jpg)
Nível 1
$ node server.js
n00bz… Processo não roda em background
![Page 51: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/51.jpg)
Nível 2
$ git pull && npm install && node server.js &
Opa… Agora tem Git, update das dependências pelo NPM e o processo roda em background
![Page 52: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/52.jpg)
Nível 3
$ git pull && npm install && nohup node server.js
Nohup roda o processo mesmo depois do logout do SSH
![Page 53: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/53.jpg)
Nível 4
$ git pull && npm install && service node-server restart
Um serviço é responsável por rodar e reiniciar o processo e salvar os logs do processo
![Page 54: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/54.jpg)
Nível 5
$ service node-server restart
Agora o servidor de CI lida com o Git e as dependências
Servidor de Continuous Integration (CI)
+
![Page 55: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/55.jpg)
Nível 6
$ pm2 reload all
Strider é o servidor de CI e o pm2 reinicia o processo on-the-fly, sem perder nenhum request
Strider (servidor de CI)
+
![Page 56: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/56.jpg)
pm2 (https://github.com/Unitech/pm2)
• Roda e gerencia os processos do Node.js (mantém processo rodando para sempre)
• Reload no código on-the-fly (zero downtime)
• Multi-thread e clusterização sem alterar uma linha de código
• Monitoramento e gerenciamento dos logs
• API RESTful + interface web
![Page 57: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/57.jpg)
Strider (https://github.com/Strider-CD/strider)
• Servidor de CI 100% em Node.js
• Integração com Github
• Monitoramento dos testes em tempo real pelo browser (com Socket.io)
• Envio de emails com erros nos testes
• Suporte a testes de regressão, custom scripts de deployment, etc.
![Page 58: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/58.jpg)
Monitoramento
![Page 59: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/59.jpg)
Saber de problemas antes dos clientes e ser transparente quando eles acontecerem.
![Page 60: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/60.jpg)
Para saber dos problemas… !
Pingdom + PagerDuty
![Page 61: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/61.jpg)
Para ser transparente sobre os problemas… !
Status Page + Twitter de status
![Page 62: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/62.jpg)
Para monitorar possíveis problemas… !
Librato
![Page 63: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/63.jpg)
![Page 64: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/64.jpg)
Conclusões…
![Page 65: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/65.jpg)
![Page 66: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/66.jpg)
… mas …
![Page 67: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/67.jpg)
![Page 68: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/68.jpg)
JavaScript
![Page 69: Node.js: serious business](https://reader034.fdocuments.net/reader034/viewer/2022042515/547e13bfb4af9fbe158b5701/html5/thumbnails/69.jpg)
Overall…