Você está na página 1de 183

Node.

js no
PEDROFRANCESCHI
@pedroh96
pedro@pagar.me
github.com/pedrofranceschi
Assuntos
Assuntos
O problema
Assuntos
O problema

Por que Node.js?


Assuntos
O problema

Por que Node.js?

Problemas de Node.js
Assuntos
O problema

Por que Node.js?

Problemas de Node.js

Node.js the right way


Assuntos
O problema

Por que Node.js?

Problemas de Node.js

Node.js the right way

Repensando a infraestrutura (+ Microservices)


Assuntos
O problema

Por que Node.js?

Problemas de Node.js

Node.js the right way

Repensando a infraestrutura (+ Microservices)

Deployment (+ Continuous Integration)


Assuntos
O problema

Por que Node.js?

Problemas de Node.js

Node.js the right way

Repensando a infraestrutura (+ Microservices)

Deployment (+ Continuous Integration)

Concluses
O problema
Montar um gateway de pagamentos
amigvel para desenvolvedores e
empreendedores
A forma mais simples de receber
pagamentos online
API RESTful

Ruby
Node.js .NET
Python
C# Java
Dashboard PHP
Angular.js
Premissas da API
Premissas da API
Simplicidade: RESTful + JSON
Premissas da API
Simplicidade: RESTful + JSON

Ambiente de testes isolado e decente


Premissas da API
Simplicidade: RESTful + JSON

Ambiente de testes isolado e decente

Segurana sem comprometer simplicidade (PCI)


Premissas da API
Simplicidade: RESTful + JSON

Ambiente de testes isolado e decente

Segurana sem comprometer simplicidade (PCI)

Uptime de 99,9%
Premissas da API
Simplicidade: RESTful + JSON

Ambiente de testes isolado e decente

Segurana sem comprometer simplicidade (PCI)

Uptime de 99,9%

Escalabilidade
Por que Node.js?
Por que Node.js?
Adquirente legtima Sistema antifraude
(Cielo, Rede, etc)
su
ce
ss
o/
er
ro

fraude
erro

API RESTful

Request de transao
Por que Node.js?
Adquirente 10.000 ms
legtima Sistema antifraude
(Cielo, Rede, etc)
su

s
ce

m
ss

0
00
o/

3.
er
ro

fraude
erro

API RESTful

Request de transao
Por que Node.js?
(no nosso caso)
Por que Node.js?
(no nosso caso)

Requests externos demorados (>1.000ms)


Por que Node.js?
(no nosso caso)

Requests externos demorados (>1.000ms)

I/O intenso em banco de dados


Por que Node.js?
(no nosso caso)

Requests externos demorados (>1.000ms)

I/O intenso em banco de dados

Totalmente assncrono, single thread e event-based


Por que Node.js?
(no nosso caso)

Requests externos demorados (>1.000ms)

I/O intenso em banco de dados

Totalmente assncrono, single thread e event-based

Alta carga na aplicao


Por que Node.js?
(no nosso caso)

Requests externos demorados (>1.000ms)

I/O intenso em banco de dados

Totalmente assncrono, single thread e event-based

Alta carga na aplicao

Pouco processamento (sem blocking de CPU)


Por que Node.js?
(no nosso caso)

Mas s usar threads em qualquer


linguagem!..
Por que Node.js?
(no nosso caso)

Mas s usar threads em qualquer


linguagem!..

No.
Por que Node.js?
(no nosso caso)

1.000 requests por segundo com conexo a uma API


externa + I/O no DB = 1.000 threads por segundo
Por que Node.js?
(no nosso caso)

1.000 requests por segundo com conexo a uma API


externa + I/O no DB = 1.000 threads por segundo

se cada request leva em mdia 10 segundos


Por que Node.js?
(no nosso caso)

1.000 requests por segundo com conexo a uma API


externa + I/O no DB = 1.000 threads por segundo

se cada request leva em mdia 10 segundos

Em 9 segundos, teremos 9.000 threads


Por que Node.js?
(no nosso caso)

1.000 requests por segundo com conexo a uma API


externa + I/O no DB = 1.000 threads por segundo

se cada request leva em mdia 10 segundos

Em 9 segundos, teremos 9.000 threads

Isso escala? :P :P :P
Por que Node.js?
(no nosso caso)

Agora, em Node.js
Por que Node.js?
(no nosso caso)

1.000 requests por segundo com conexo a uma API


externa + I/O no DB = 1 thread
Por que Node.js?
(no nosso caso)

1.000 requests por segundo com conexo a uma API


externa + I/O no DB = 1 thread

se cada request leva em mdia 10 segundos


Por que Node.js?
(no nosso caso)

1.000 requests por segundo com conexo a uma API


externa + I/O no DB = 1 thread

se cada request leva em mdia 10 segundos

Em 9 segundos, teremos 1 thread


Por que Node.js?
(no nosso caso)

1.000 requests por segundo com conexo a uma API


externa + I/O no DB = 1 thread

se cada request leva em mdia 10 segundos

Em 9 segundos, teremos 1 thread

Isso escala? Sim.


Por que Node.js?
(no nosso caso)

1.000 requests por segundo com conexo a uma API


externa + I/O no DB = 1 thread

se cada request leva em mdia 10 segundos

Em 9 segundos, teremos 1 thread

Isso escala? Sim.


#eventloopFTW
I/O sncrona

Aplicao

Sistema operacional
I/O sncrona
I/O

Aplicao

Sistema operacional
I/O sncrona
I/O

Aplicao

Sistema operacional
I/O sncrona
I/O

Aplicao

I/O bloqueante
(aplicao travada)

Sistema operacional
I/O sncrona
I/O

Aplicao

I/O bloqueante
(aplicao travada)

Sistema operacional
I/O sncrona
I/O
retorno

Aplicao

I/O bloqueante
(aplicao travada)

Sistema operacional
I/O sncrona
I/O I/O
retorno retorno

Aplicao

I/O bloqueante I/O bloqueante


(aplicao travada) (aplicao travada)

Sistema operacional
I/O sncrona
I/O I/O I/O
retorno retorno retorno

Aplicao

I/O bloqueante I/O bloqueante I/O bloqueante


(aplicao travada) (aplicao travada) (aplicao travada)

Sistema operacional
I/O assncrona com threads

Aplicao

Sistema operacional
I/O assncrona com threads
I/O

Aplicao

Sistema operacional
I/O assncrona com threads
I/O

Aplicao

Sistema operacional
I/O assncrona com threads
I/O

Aplicao

Thread

Sistema operacional
I/O assncrona com threads
I/O

Aplicao

Thread

Sistema operacional
I/O assncrona com threads
I/O

Aplicao

Thread

I/O bloqueante
(thread travada)

Sistema operacional
I/O assncrona com threads
I/O

Aplicao

Thread

I/O bloqueante
(thread travada)

Sistema operacional
I/O assncrona com threads
I/O

Aplicao

Thread

I/O bloqueante
(thread travada)

Sistema operacional
I/O assncrona com threads
I/O
callback

Aplicao

Thread

I/O bloqueante
(thread travada)

Sistema operacional
I/O assncrona com threads
I/O I/O
callback callback

Aplicao

Thread Thread

I/O bloqueante I/O bloqueante


(thread travada) (thread travada)

Sistema operacional
I/O assncrona com threads
I/O I/O I/O
callback callback callback

Aplicao

Thread Thread Thread

I/O bloqueante I/O bloqueante I/O bloqueante


(thread travada) (thread travada) (thread travada)

Sistema operacional
O segredo do Node.js

JavaScript (event loop)

V8

libuv

Sistema operacional
O segredo do Node.js
I/O

JavaScript (event loop)

V8

libuv

Sistema operacional
O segredo do Node.js
I/O

JavaScript (event loop)

V8

libuv

Sistema operacional
O segredo do Node.js
I/O

JavaScript (event loop)

V8

libuv

Sistema operacional
O segredo do Node.js
I/O

JavaScript (event loop)

V8

libuv

Sistema operacional
O segredo do Node.js
I/O

JavaScript (event loop)

V8

libuv

Sistema operacional

O segredo do Node.js
I/O

JavaScript (event loop)

V8

libuv

Sistema operacional

operaes assncronas em nvel de OS
O segredo do Node.js
I/O

JavaScript (event loop)

V8

libuv

Sistema operacional

operaes assncronas em nvel de OS
O segredo do Node.js
I/O

JavaScript (event loop)

V8

libuv

Sistema operacional

operaes assncronas em nvel de OS
O segredo do Node.js
I/O

JavaScript (event loop)

V8

libuv

Sistema operacional

operaes assncronas em nvel de OS
O segredo do Node.js
I/O
callback

JavaScript (event loop)

V8

libuv

Sistema operacional

operaes assncronas em nvel de OS
O segredo do Node.js
I/O
I/O
callback

JavaScript (event loop)

V8

libuv

Sistema operacional

operaes assncronas em nvel de OS
O segredo do Node.js
I/O
I/O
callback

JavaScript (event loop)

V8

libuv

Sistema operacional


operaes assncronas em nvel de OS
O segredo do Node.js
I/O
I/O
I/O callback

JavaScript (event loop)

V8

libuv

Sistema operacional


operaes assncronas em nvel de OS
O segredo do Node.js
I/O
I/O
I/O callback

JavaScript (event loop)

V8

libuv

Sistema operacional



operaes assncronas em nvel de OS
O segredo do Node.js
I/O callback
I/O
I/O callback

JavaScript (event loop)

V8

libuv

Sistema operacional



operaes assncronas em nvel de OS
O segredo do Node.js
I/O callback
I/O callback
I/O callback

JavaScript (event loop)

V8

libuv

Sistema operacional



operaes assncronas em nvel de OS
Node.js escala em I/O bloqueante, no
em utilizao de CPU
(threads so boas em processamento paralelo)
Problemas de Node.js
Problemas de Node.js
Cdigo assncrono (race conditions, callback hell,
testes assncronos, 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 no fazer: callback hell.
Problemas de Node.js
Problemas de Javascript: bizarrices e facilidade em no
seguir padres e orientao a objetos.

> 0.1+0.2
0.30000000000000004

> typeof NaN


'number'

> NaN === NaN


false

Cortesia do wtfjs.com
Problemas de Node.js
Exceptions no 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);

$ node test.js
Tamanho do primeiro nome: 5
Tamanho do segundo nome: 10
Problemas de Node.js
Exceptions no 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);

$ 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
Problemas de Node.js
Problemas de Node.js

Single thread (escalar horizontalmente e


verticalmente com mltiplas instncias)
Problemas de Node.js

Single thread (escalar horizontalmente e


verticalmente com mltiplas instncias)

Leaks de memria difceis de detectar (back-end em


C++, variveis globalizadas, closures, etc)
Problemas de Node.js

Single thread (escalar horizontalmente e


verticalmente com mltiplas instncias)

Leaks de memria difceis de detectar (back-end em


C++, variveis globalizadas, closures, etc)

Programadores front-end mexendo em back-end


( tudo Javascript!!)
Problemas de Node.js

Single thread (escalar horizontalmente e


verticalmente com mltiplas instncias)

Leaks de memria difceis de detectar (back-end em


C++, variveis globalizadas, closures, etc)

Programadores front-end mexendo em back-end


( tudo Javascript!!)

Existe a 6 anos, porm ainda beta (v0.12.0) - e s


vezes voc precisa usar unstable em produo
Node.js the right way
Qualidade de vida vs. tempo usando Node
Qualidade de vida vs. tempo usando Node

Node muito
legal!!!
Qualidade de vida vs. tempo usando Node

Node muito
legal!!! Ops Meu cdigo est
ficando uma zona
Qualidade de vida vs. tempo usando Node

Node muito
legal!!! Ops Meu cdigo est
ficando uma zona

Queria ter feito em


Rails
MVC de verdade +
Promise + Bluebird <3
Qualidade de vida vs. tempo usando Node

Node muito
legal!!! Ops Meu cdigo est
ficando uma zona

Queria ter feito em


Rails
Node.js the right way
Modules

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
Node.js the right way
Testes (JavaScript quebra)
(https://github.com/visionmedia/mocha e https://github.com/visionmedia/should.js/)

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);
})
})
});
Node.js the right way
Models (Sequelize/Mongoose)
var Transaction = Sequelize.define('Transaction', {
amount: Sequelize.INTEGER,
cost: Sequelize.FLOAT,
status: {
type: Sequelize.ENUM,
values: ['paid', 'refused', 'refunded'],
defaultValue: 'processing'
}
}, {
instanceMethods: {
calculateCost: function(status){
status = status || this.status;

if(status == 'paid') {
return 50 + (this.amount * 0.015);
}
},
},
classMethods: {
},
hooks: {
beforeUpdate: function(transaction) {
return transaction.calculateCost()
.then(function(cost) {
transaction.cost = cost;
});
}
},
});
Node.js the right way
Models (Sequelize/Mongoose)
var Transaction = Sequelize.define('Transaction', {
amount: Sequelize.INTEGER,
cost: Sequelize.FLOAT,
status: {
type: Sequelize.ENUM,
values: ['paid', 'refused', 'refunded'],
defaultValue: 'processing'
}
}, {
instanceMethods: {
calculateCost: function(status){
status = status || this.status;

if(status == 'paid') {
return 50 + (this.amount * 0.015);
}
},
},
classMethods: {
},
hooks: {
beforeUpdate: function(transaction) {
return transaction.calculateCost()
.then(function(cost) {
transaction.cost = cost;
});
}
},
});
Node.js the right way
Models (Sequelize/Mongoose)
var Transaction = Sequelize.define('Transaction', {
amount: Sequelize.INTEGER,
cost: Sequelize.FLOAT,
status: {
type: Sequelize.ENUM,
values: ['paid', 'refused', 'refunded'],
defaultValue: 'processing'
}
}, {
instanceMethods: {
calculateCost: function(status){
status = status || this.status;

if(status == 'paid') {
return 50 + (this.amount * 0.015);
}
},
},
classMethods: {
},
hooks: {
beforeUpdate: function(transaction) {
return transaction.calculateCost()
.then(function(cost) {
transaction.cost = cost;
});
}
},
});
Node.js the right way
Models (Sequelize/Mongoose)
var Transaction = Sequelize.define('Transaction', {
amount: Sequelize.INTEGER,
cost: Sequelize.FLOAT,
status: {
type: Sequelize.ENUM,
values: ['paid', 'refused', 'refunded'],
defaultValue: 'processing'
}
}, {
instanceMethods: {
calculateCost: function(status){
status = status || this.status;

if(status == 'paid') {
return 50 + (this.amount * 0.015);
}
},
},
classMethods: {
},
hooks: {
beforeUpdate: function(transaction) {
return transaction.calculateCost()
.then(function(cost) {
transaction.cost = cost;
});
}
},
});
Node.js the right way
Models (Sequelize/Mongoose)
var Transaction = Sequelize.define('Transaction', {
amount: Sequelize.INTEGER,
cost: Sequelize.FLOAT,
status: {
type: Sequelize.ENUM,
values: ['paid', 'refused', 'refunded'],
defaultValue: 'processing'
}
}, {
instanceMethods: {
calculateCost: function(status){
status = status || this.status;

if(status == 'paid') {
return 50 + (this.amount * 0.015);
}
},
},
classMethods: {
},
hooks: {
beforeUpdate: function(transaction) {
return transaction.calculateCost()
.then(function(cost) {
transaction.cost = cost;
});
}
},
});
Node.js the right way
Promises (Bluebird)

fs.readFile("file.json", function(err, val) {


if(err) {
console.error("unable to read file");
} else {
try {
val = JSON.parse(val);
console.log(val.success);
} catch(e) {
console.error("invalid json in file");
}
}
});
Node.js the right way
Promises (Bluebird)

fs.readFile("file.json", function(err, val) {


if(err) {
console.error("unable to read file");
} else {
try {
val = JSON.parse(val);
console.log(val.success);
} catch(e) {
console.error("invalid json in file");
}
}
});
Node.js the right way
Promises (Bluebird)

fs.readFileAsync("file.json").then(JSON.parse).then(function(val) {
console.log(val.success);
})
.catch(SyntaxError, function(e) {
console.error("invalid json in file");
})
.catch(function(e){
console.error("unable to read file")
});

Assim bem melhor :)


Node.js the right way
Lodash

var lines = [
['name', 'type', 'cost'],
['iPhone', 'cellphone', '2000'], Output
['MacBook', 'computer', '10000'],
['iPad', 'tablet', '1500'] name,type,cost
]; iPhone,cellphone,2000
MacBook,computer,10000
var joinedLines = []; iPad,tablet,1500

for(var i = 0; i < lines.length; i++) {


joinedLines.push(lines[i].join(','));
}

var csvContent = joinedLines.join('\n');


Node.js the right way
Lodash

var lines = [
['name', 'type', 'cost'],
['iPhone', 'cellphone', '2000'], Output
['MacBook', 'computer', '10000'],
['iPad', 'tablet', '1500'] name,type,cost
]; iPhone,cellphone,2000
MacBook,computer,10000
var joinedLines = []; iPad,tablet,1500

for(var i = 0; i < lines.length; i++) {


joinedLines.push(lines[i].join(','));
}

var csvContent = joinedLines.join('\n');


Node.js the right way
Lodash

var lines = [
['name', 'type', 'cost'],
['iPhone', 'cellphone', '2000'], Output
['MacBook', 'computer', '10000'],
['iPad', 'tablet', '1500'] name,type,cost
]; iPhone,cellphone,2000
MacBook,computer,10000
var joinedLines = []; iPad,tablet,1500

for(var i = 0; i < lines.length; i++) {


joinedLines.push(lines[i].join(','));
}

var csvContent = joinedLines.join('\n');


Node.js the right way
Lodash

var _ = require('lodash');

var lines = [
['name', 'type', 'cost'],
['iPhone', 'cellphone', '2000'], Output
['MacBook', 'computer', '10000'],
['iPad', 'tablet', '1500'] name,type,cost
]; iPhone,cellphone,2000
MacBook,computer,10000
var csvContent = _.map(lines, function(line){ iPad,tablet,1500
return line.join(',');
}).join('\n');

Assim bem melhor :)


Node.js the right way
Node.js the right way

Seguir e manter um code style (dica: Google


JavaScript Style Guide)
Node.js the right way

Seguir e manter um code style (dica: Google


JavaScript Style Guide)

Tratamento de erros consistente via Promise (evitar


que processos morram)
Node.js the right way

Seguir e manter um code style (dica: Google


JavaScript Style Guide)

Tratamento de erros consistente via Promise (evitar


que processos morram)

Manter consistncia entre as bibliotecas de Promise


(i.e. usar a mesma do wrapper do database)
Node.js the right way

Seguir e manter um code style (dica: Google


JavaScript Style Guide)

Tratamento de erros consistente via Promise (evitar


que processos morram)

Manter consistncia entre as bibliotecas de Promise


(i.e. usar a mesma do wrapper do database)

Sem for(var i = 0; i < object.length; i++) - #lodashFTW


Node.js the right way
utils
Node.js the right way
utils

Express.js: lightweight HTTP framework


Node.js the right way
utils

Express.js: lightweight HTTP framework

Sequelize: ORM de MySQL, PostgreSQL, sqlite3, etc.


Node.js the right way
utils

Express.js: lightweight HTTP framework

Sequelize: ORM de MySQL, PostgreSQL, sqlite3, etc.

Mongoose: ORM de MongoDB


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


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


Repensando a infraestrutura
Infraestrutura do Pagar.me

Servidor da API Servidor da API


(Node.js) (Node.js)

Router
Ambiente de testes Ambiente de produo
(sandbox dos clientes)
api.pagar.me
Infraestrutura do Pagar.me

ElasticSearch ElasticSearch

Servidor da API Servidor da API


(Node.js) (Node.js)

Router
Ambiente de testes Ambiente de produo
(sandbox dos clientes)
api.pagar.me
Infraestrutura do Pagar.me

MySQL MySQL
(transaes e dados relacionais) (transaes e dados relacionais)

ElasticSearch ElasticSearch

Servidor da API Servidor da API


(Node.js) (Node.js)

Router
Ambiente de testes Ambiente de produo
(sandbox dos clientes)
api.pagar.me
Infraestrutura do Pagar.me
Redis Redis
+ +
MySQL MySQL
(transaes e dados relacionais) (transaes e dados relacionais)

ElasticSearch ElasticSearch

Servidor da API Servidor da API


(Node.js) (Node.js)

Router
Ambiente de testes Ambiente de produo
(sandbox dos clientes)
api.pagar.me
Infraestrutura do Pagar.me
Redis Redis
+ +
MySQL MongoDB MySQL
(transaes e dados relacionais) (dados de clientes e no relacionais) (transaes e dados relacionais)

ElasticSearch ElasticSearch

Servidor da API Servidor da API


(Node.js) (Node.js)

Router
Ambiente de testes Ambiente de produo
(sandbox dos clientes)
api.pagar.me
Por que tantos bancos?
Por que tantos bancos?
Separar dados de teste (sandbox dos clientes) dos dados de
produo
Por que tantos bancos?
Separar dados de teste (sandbox dos clientes) dos dados de
produo

MySQL: dados relacionais (transaes, assinaturas, planos,


cartes, etc.)
Por que tantos bancos?
Separar dados de teste (sandbox dos clientes) dos dados de
produo

MySQL: dados relacionais (transaes, assinaturas, planos,


cartes, etc.)

MongoDB: dados no-relacionais (informaes do cliente,


usurios de uma conta, etc.)
Por que tantos bancos?
Separar dados de teste (sandbox dos clientes) dos dados de
produo

MySQL: dados relacionais (transaes, assinaturas, planos,


cartes, etc.)

MongoDB: dados no-relacionais (informaes do cliente,


usurios de uma conta, etc.)

ElasticSearch: indexao/buscas ultra-rpidas (expondo uma


engine de buscas poderosa para os clientes)
Por que tantos bancos?
Separar dados de teste (sandbox dos clientes) dos dados de
produo

MySQL: dados relacionais (transaes, assinaturas, planos,


cartes, etc.)

MongoDB: dados no-relacionais (informaes do cliente,


usurios de uma conta, etc.)

ElasticSearch: indexao/buscas ultra-rpidas (expondo uma


engine de buscas poderosa para os clientes)

Redis: fila para notificaes entre servios


Por que tantos bancos?
Separar dados de teste (sandbox dos clientes) dos dados de
produo

MySQL: dados relacionais (transaes, assinaturas, planos,


cartes, etc.)

MongoDB: dados no-relacionais (informaes do cliente,


usurios de uma conta, etc.)

ElasticSearch: indexao/buscas ultra-rpidas (expondo uma


engine de buscas poderosa para os clientes)

Redis: fila para notificaes entre servios


No h porque se prender a uma tecnologia quando cada uma
delas resolve uma parte do seu problema
Infraestrutura do Pagar.me
Redis Redis
+ +
MySQL MongoDB MySQL
(transaes e dados relacionais) (dados de clientes e no relacionais) (transaes e dados relacionais)

ElasticSearch ElasticSearch

Servidor da API Servidor da API


(Node.js) (Node.js)

Router
Ambiente de testes Ambiente de produo
(sandbox dos clientes)
api.pagar.me
Infraestrutura do Pagar.me
Redis Redis
+ +
MySQL MongoDB MySQL
(transaes e dados relacionais) (dados de clientes e no relacionais) (transaes e dados relacionais)

ElasticSearch ElasticSearch

Servidor da API Servidor da API


(Node.js) (Node.js)

Router
Ambiente de testes Ambiente de produo
(sandbox dos clientes)
api.pagar.me
Microservices
Cliente
node gateway.js -p 5000

node api.js -p 3000

Cliente
node gateway.js -p 5000

node api.js -p 3000


API RESTful (pagar.me/docs)

Cliente
node gateway.js -p 5000

API RESTful
(servio interno)

node api.js -p 3000


API RESTful (pagar.me/docs)

Cliente
XML, SOAP, ISO 8583, X25, sinal de fumaa :P

node gateway.js -p 5000

API RESTful
(servio interno)

node api.js -p 3000


API RESTful (pagar.me/docs)

Cliente
XML, SOAP, ISO 8583, X25, sinal de fumaa :P

node gateway.js -p 5000

API RESTful
~ 550 ms
(servio interno)

node api.js -p 3000


API RESTful (pagar.me/docs)

Cliente
XML, SOAP, ISO 8583, X25, sinal de fumaa :P

node gateway.js -p 5000

API RESTful
~ 550 ms
(servio interno)

node api.js -p 3000


~ 500ms API RESTful (pagar.me/docs)

Cliente
> 5000 ms XML, SOAP, ISO 8583, X25, sinal de fumaa :P

node gateway.js -p 5000

API RESTful
~ 550 ms
(servio interno)

node api.js -p 3000


~ 500ms API RESTful (pagar.me/docs)

Cliente
> 5000 ms XML, SOAP, ISO 8583, X25, sinal de fumaa :P

node gateway.js -p 5000

API RESTful
~ 550 ms
(servio interno) node hookshot.js

node api.js -p 3000


~ 500ms API RESTful (pagar.me/docs)

Cliente
> 5000 ms XML, SOAP, ISO 8583, X25, sinal de fumaa :P

node gateway.js -p 5000


Redis (queue)

API RESTful
~ 550 ms
(servio interno) node hookshot.js

node api.js -p 3000


~ 500ms API RESTful (pagar.me/docs)

Cliente
> 5000 ms XML, SOAP, ISO 8583, X25, sinal de fumaa :P

node gateway.js -p 5000


Redis (queue)

API RESTful
~ 550 ms
(servio interno) node hookshot.js

node api.js -p 3000 Request HTTP para


o servidor do cliente

~ 500ms API RESTful (pagar.me/docs)

Cliente
> 5000 ms XML, SOAP, ISO 8583, X25, sinal de fumaa :P

node gateway.js -p 5000


Redis (queue)

API RESTful
~ 550 ms
(servio interno) node hookshot.js

node api.js -p 3000 ~ 100 ms


Request HTTP para
o servidor do cliente

~ 500ms API RESTful (pagar.me/docs)

Cliente
Deployment
Nvel 1

$ node server.js

n00bz Processo no roda em background


Nvel 2

$ git pull && npm install && node server.js &

Opa Agora tem Git, update das dependncias pelo NPM e o


processo roda em background
Nvel 3

$ git pull && npm install && nohup node server.js

Nohup roda o processo mesmo depois do logout do SSH


Nvel 4

$ git pull && npm install && service node-server restart

Um servio responsvel por rodar e reiniciar o processo e


salvar os logs do processo
Nvel 5

Servidor de Continuous Integration (CI)

+
$ service node-server restart

Agora o servidor de CI lida com o Git e as dependncias


pm2
(https://github.com/Unitech/pm2)
pm2
(https://github.com/Unitech/pm2)

Roda e gerencia os processos do Node.js (mantm


processo rodando para sempre)
pm2
(https://github.com/Unitech/pm2)

Roda e gerencia os processos do Node.js (mantm


processo rodando para sempre)

Reload no cdigo on-the-fly (zero downtime)


pm2
(https://github.com/Unitech/pm2)

Roda e gerencia os processos do Node.js (mantm


processo rodando para sempre)

Reload no cdigo on-the-fly (zero downtime)

Multi-thread e clusterizao sem alterar uma linha de


cdigo
pm2
(https://github.com/Unitech/pm2)

Roda e gerencia os processos do Node.js (mantm


processo rodando para sempre)

Reload no cdigo on-the-fly (zero downtime)

Multi-thread e clusterizao sem alterar uma linha de


cdigo

Monitoramento e gerenciamento dos logs


pm2
(https://github.com/Unitech/pm2)

Roda e gerencia os processos do Node.js (mantm


processo rodando para sempre)

Reload no cdigo on-the-fly (zero downtime)

Multi-thread e clusterizao sem alterar uma linha de


cdigo

Monitoramento e gerenciamento dos logs

API RESTful + interface web


Nvel 6

Strider (servidor de CI)

+
$ pm2 reload all

Strider o servidor de CI e o pm2 reinicia o processo on-the-fly,


sem perder nenhum request
Nvel 7 (ChatOps)

Janky (Jenkins) + Heaven + Hubot

+
$ pm2 reload all

Janky o servidor de CI, Heaven o servidor de deployment e o


pm2 reinicia o processo on-the-fly, sem perder nenhum request
ChatOps
ChatOps
Todos os commits so testados (via Janky + Jenkins)
ChatOps
Todos os commits so testados (via Janky + Jenkins)

Todas as branches tm um estado (green/no-green)


ChatOps
Todos os commits so testados (via Janky + Jenkins)

Todas as branches tm um estado (green/no-green)

Todas as branches green podem ser deployadas (sem


regresso)
ChatOps
Todos os commits so testados (via Janky + Jenkins)

Todas as branches tm um estado (green/no-green)

Todas as branches green podem ser deployadas (sem


regresso)

Tudo acontece integrado ao GitHub


ChatOps
Todos os commits so testados (via Janky + Jenkins)

Todas as branches tm um estado (green/no-green)

Todas as branches green podem ser deployadas (sem


regresso)

Tudo acontece integrado ao GitHub

Deploy da branch X (via Heaven) para um servidor ou


grupo de servidores
ChatOps
Todos os commits so testados (via Janky + Jenkins)

Todas as branches tm um estado (green/no-green)

Todas as branches green podem ser deployadas (sem


regresso)

Tudo acontece integrado ao GitHub

Deploy da branch X (via Heaven) para um servidor ou


grupo de servidores

Tudo acontece numa sala de bate papo com todas as


pessoas relacionadas ao projeto.
$ hubot ci build pagarme-api/boleto_upgrade
$ hubot ci build pagarme-api/boleto_upgrade

$ hubot deploy pagarme-api/boleto_upgrade to prod-test/api01


$ hubot ci build pagarme-api/boleto_upgrade

$ hubot deploy pagarme-api/boleto_upgrade to prod-test/api01

$ alias sharon=hubot
$ sharon ci build pagarme-api/boleto_upgrade

$ sharon deploy pagarme-api/boleto_upgrade to prod-test/api01

$ alias sharon=hubot
Concluses
Obrigado! :)
PEDROFRANCESCHI
@pedroh96
pedro@pagar.me
github.com/pedrofranceschi
Node.js no
PEDROFRANCESCHI
@pedroh96
pedro@pagar.me
github.com/pedrofranceschi