js no
PEDROFRANCESCHI
@pedroh96
pedro@pagar.me
github.com/pedrofranceschi
Assuntos
Assuntos
O problema
Assuntos
O problema
Problemas de Node.js
Assuntos
O problema
Problemas de Node.js
Problemas de Node.js
Problemas de Node.js
Problemas de Node.js
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
Uptime de 99,9%
Premissas da API
Simplicidade: RESTful + JSON
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)
No.
Por que Node.js?
(no nosso caso)
Isso escala? :P :P :P
Por que Node.js?
(no nosso caso)
Agora, em Node.js
Por que Node.js?
(no nosso caso)
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
Sistema operacional
I/O sncrona
I/O I/O I/O
retorno retorno retorno
Aplicao
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
Sistema operacional
I/O assncrona com threads
I/O I/O I/O
callback callback callback
Aplicao
Sistema operacional
O segredo do Node.js
V8
libuv
Sistema operacional
O segredo do Node.js
I/O
V8
libuv
Sistema operacional
O segredo do Node.js
I/O
V8
libuv
Sistema operacional
O segredo do Node.js
I/O
V8
libuv
Sistema operacional
O segredo do Node.js
I/O
V8
libuv
Sistema operacional
O segredo do Node.js
I/O
V8
libuv
Sistema operacional
O segredo do Node.js
I/O
V8
libuv
Sistema operacional
operaes assncronas em nvel de OS
O segredo do Node.js
I/O
V8
libuv
Sistema operacional
operaes assncronas em nvel de OS
O segredo do Node.js
I/O
V8
libuv
Sistema operacional
operaes assncronas em nvel de OS
O segredo do Node.js
I/O
V8
libuv
Sistema operacional
operaes assncronas em nvel de OS
O segredo do Node.js
I/O
callback
V8
libuv
Sistema operacional
operaes assncronas em nvel de OS
O segredo do Node.js
I/O
I/O
callback
V8
libuv
Sistema operacional
operaes assncronas em nvel de OS
O segredo do Node.js
I/O
I/O
callback
V8
libuv
Sistema operacional
operaes assncronas em nvel de OS
O segredo do Node.js
I/O
I/O
I/O callback
V8
libuv
Sistema operacional
operaes assncronas em nvel de OS
O segredo do Node.js
I/O
I/O
I/O callback
V8
libuv
Sistema operacional
operaes assncronas em nvel de OS
O segredo do Node.js
I/O callback
I/O
I/O callback
V8
libuv
Sistema operacional
operaes assncronas em nvel de OS
O segredo do Node.js
I/O callback
I/O callback
I/O callback
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)
> 0.1+0.2
0.30000000000000004
Cortesia do wtfjs.com
Problemas de Node.js
Exceptions no tratadas matam o processo.
var name = Pedro Franceschi";
$ 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";
$ 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
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
Node muito
legal!!! Ops Meu cdigo est
ficando uma zona
var PI = Math.PI;
circle.js
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);
})
})
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.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")
});
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
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
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
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');
Router
Ambiente de testes Ambiente de produo
(sandbox dos clientes)
api.pagar.me
Infraestrutura do Pagar.me
ElasticSearch ElasticSearch
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
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
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
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
ElasticSearch ElasticSearch
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
Router
Ambiente de testes Ambiente de produo
(sandbox dos clientes)
api.pagar.me
Microservices
Cliente
node gateway.js -p 5000
Cliente
node gateway.js -p 5000
Cliente
node gateway.js -p 5000
API RESTful
(servio interno)
Cliente
XML, SOAP, ISO 8583, X25, sinal de fumaa :P
API RESTful
(servio interno)
Cliente
XML, SOAP, ISO 8583, X25, sinal de fumaa :P
API RESTful
~ 550 ms
(servio interno)
Cliente
XML, SOAP, ISO 8583, X25, sinal de fumaa :P
API RESTful
~ 550 ms
(servio interno)
Cliente
> 5000 ms XML, SOAP, ISO 8583, X25, sinal de fumaa :P
API RESTful
~ 550 ms
(servio interno)
Cliente
> 5000 ms XML, SOAP, ISO 8583, X25, sinal de fumaa :P
API RESTful
~ 550 ms
(servio interno) node hookshot.js
Cliente
> 5000 ms XML, SOAP, ISO 8583, X25, sinal de fumaa :P
API RESTful
~ 550 ms
(servio interno) node hookshot.js
Cliente
> 5000 ms XML, SOAP, ISO 8583, X25, sinal de fumaa :P
API RESTful
~ 550 ms
(servio interno) node hookshot.js
Cliente
> 5000 ms XML, SOAP, ISO 8583, X25, sinal de fumaa :P
API RESTful
~ 550 ms
(servio interno) node hookshot.js
Cliente
Deployment
Nvel 1
$ node server.js
+
$ service node-server restart
+
$ pm2 reload all
+
$ pm2 reload all
$ alias sharon=hubot
$ sharon ci build pagarme-api/boleto_upgrade
$ alias sharon=hubot
Concluses
Obrigado! :)
PEDROFRANCESCHI
@pedroh96
pedro@pagar.me
github.com/pedrofranceschi
Node.js no
PEDROFRANCESCHI
@pedroh96
pedro@pagar.me
github.com/pedrofranceschi