Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Desafíos y lecciones aprendidas haciendo grande...

Backbeam
October 19, 2013

Desafíos y lecciones aprendidas haciendo grandes aplicaciones con Node.js

Backbeam

October 19, 2013
Tweet

More Decks by Backbeam

Other Decks in Programming

Transcript

  1. Quién soy...? @gimenete @backbeamio Alberto Gimeno • Alberto Gimeno @gimenete

    • Programador, emprendedor Saturday, October 19, 13
  2. Quién soy...? @gimenete @backbeamio Alberto Gimeno • Alberto Gimeno @gimenete

    • Programador, emprendedor • Usando nodejs desde 2010 Saturday, October 19, 13
  3. Quién soy...? @gimenete @backbeamio Alberto Gimeno • Alberto Gimeno @gimenete

    • Programador, emprendedor • Usando nodejs desde 2010 • Emprendiendo desde 2005 Saturday, October 19, 13
  4. JavaScript el más odiado y amado a la vez @gimenete

    @backbeamio Alberto Gimeno Saturday, October 19, 13
  5. JavaScript el más odiado y amado a la vez @gimenete

    @backbeamio Alberto Gimeno • Un lenguaje, múltiples runtimes Saturday, October 19, 13
  6. JavaScript el más odiado y amado a la vez @gimenete

    @backbeamio Alberto Gimeno • Un lenguaje, múltiples runtimes • Un lenguaje dinámico como cualquier otro, salvo que está por todas partes Saturday, October 19, 13
  7. JavaScript el más odiado y amado a la vez @gimenete

    @backbeamio Alberto Gimeno • Un lenguaje, múltiples runtimes • Un lenguaje dinámico como cualquier otro, salvo que está por todas partes • Con sus WAT?! Como cualquier otro Saturday, October 19, 13
  8. Encapsulación sin this ni prototype @gimenete @backbeamio Alberto Gimeno function

    parser() { ! var obj = {} // variables y métodos "públicos" ! var n = 1 // variables "privadas" ! // función "privada" ! function foo() {} ! // método público ! obj.bar = function () {} ! return obj } Saturday, October 19, 13
  9. Flujo de ejecución @gimenete @backbeamio Alberto Gimeno var arr =

    [1, 2, 3] for (var i = 0; i < arr.length; i++) { somethingAsync(arr[i], function() { console.log(arr[i]) }) } Saturday, October 19, 13
  10. Flujo de ejecución @gimenete @backbeamio Alberto Gimeno var arr =

    [1, 2, 3] for (var i = 0; i < arr.length; i++) { somethingAsync(arr[i], function() { console.log(arr[i]) }) } $ node example.js undefined undefined undefined Saturday, October 19, 13
  11. Flujo de ejecución @gimenete @backbeamio Alberto Gimeno var arr =

    [1, 2, 3] for (var i = 0; i < arr.length; i++) { somethingAsync(arr[i], function() { console.log(arr[i]) }) } $ node example.js undefined undefined undefined Saturday, October 19, 13
  12. Flujo de ejecución @gimenete @backbeamio Alberto Gimeno var arr =

    [1, 2, 3] for (var i = 0; i < arr.length; i++) { var item = arr[i] somethingAsync(item, function() { console.log(item) }) } Saturday, October 19, 13
  13. Flujo de ejecución @gimenete @backbeamio Alberto Gimeno $ node example.js

    3 3 3 var arr = [1, 2, 3] for (var i = 0; i < arr.length; i++) { var item = arr[i] somethingAsync(item, function() { console.log(item) }) } Saturday, October 19, 13
  14. Flujo de ejecución @gimenete @backbeamio Alberto Gimeno $ node example.js

    3 3 3 var arr = [1, 2, 3] for (var i = 0; i < arr.length; i++) { var item = arr[i] somethingAsync(item, function() { console.log(item) }) } Saturday, October 19, 13
  15. Flujo de ejecución @gimenete @backbeamio Alberto Gimeno var arr =

    [1, 2, 3] async.eachSeries(arr, function(item, next) { console.log(item) somethingAsync(item, next) }, function() { console.log('done!') }) Saturday, October 19, 13
  16. Flujo de ejecución @gimenete @backbeamio Alberto Gimeno $ node example.js

    1 2 3 done! var arr = [1, 2, 3] async.eachSeries(arr, function(item, next) { console.log(item) somethingAsync(item, next) }, function() { console.log('done!') }) Saturday, October 19, 13
  17. Flujo de ejecución @gimenete @backbeamio Alberto Gimeno $ node example.js

    1 2 3 done! var arr = [1, 2, 3] async.eachSeries(arr, function(item, next) { console.log(item) somethingAsync(item, next) }, function() { console.log('done!') }) Hay otras muchas funciones: each(), eachLimit(), map, filter,... https://github.com/caolan/async Saturday, October 19, 13
  18. Flujo de ejecución: combatir la pirámide @gimenete @backbeamio Alberto Gimeno

    function f1(cb) { ... } function f2(cb) { ... } async.series([f1, f2], function() { console.log('done!') }) Saturday, October 19, 13
  19. ¿Promesas? @gimenete @backbeamio Alberto Gimeno • ✗ No resuelven la

    pirámide de la muerte Saturday, October 19, 13
  20. ¿Promesas? @gimenete @backbeamio Alberto Gimeno • ✗ No resuelven la

    pirámide de la muerte • ✓Desacoplan y gestionan el flujo Saturday, October 19, 13
  21. ¿Promesas? @gimenete @backbeamio Alberto Gimeno • ✗ No resuelven la

    pirámide de la muerte • ✓Desacoplan y gestionan el flujo • ✗ Nada que no puedas hacer con async Saturday, October 19, 13
  22. ¿Promesas? @gimenete @backbeamio Alberto Gimeno • ✗ No resuelven la

    pirámide de la muerte • ✓Desacoplan y gestionan el flujo • ✗ Nada que no puedas hacer con async • ✗ Añaden dependencias, incompatibilidades, y complejidades Saturday, October 19, 13
  23. ¿Promesas? @gimenete @backbeamio Alberto Gimeno • ✗ No resuelven la

    pirámide de la muerte • ✓Desacoplan y gestionan el flujo • ✗ Nada que no puedas hacer con async • ✗ Añaden dependencias, incompatibilidades, y complejidades http://gimenete.tumblr.com/post/47528626262/los-programadores-no- necesitamos-vanas-promesas Saturday, October 19, 13
  24. Lidiando con el asincronismo @gimenete @backbeamio Alberto Gimeno function absolute(n,

    cb) { if (n >= 0) { cb(null, n) } cb(null, -n) } Saturday, October 19, 13
  25. Lidiando con el asincronismo @gimenete @backbeamio Alberto Gimeno function absolute(n,

    cb) { if (n >= 0) { cb(null, n) } cb(null, -n) } ✗ La función no termina aquí, cb llamado dos veces! Saturday, October 19, 13
  26. Solución: return @gimenete @backbeamio Alberto Gimeno function absolute(n, cb) {

    if (n >= 0) { return cb(null, n) } cb(null, -n) } Saturday, October 19, 13
  27. Solución: return @gimenete @backbeamio Alberto Gimeno function absolute(n, cb) {

    if (n >= 0) { return cb(null, n) } cb(null, -n) } Podemos poner return delante y el código queda más compacto Saturday, October 19, 13
  28. Funciones falsamente asíncronas (ej: la anterior :) @gimenete @backbeamio Alberto

    Gimeno function absolute(n, cb) { if (n >= 0) { return cb(null, n) } cb(null, -n) } absolute(-3, function(err, n) { console.log('foo') }) console.log('bar') Saturday, October 19, 13
  29. Funciones falsamente asíncronas (ej: la anterior :) @gimenete @backbeamio Alberto

    Gimeno ¿Qué aparece primero en la consola? function absolute(n, cb) { if (n >= 0) { return cb(null, n) } cb(null, -n) } absolute(-3, function(err, n) { console.log('foo') }) console.log('bar') Saturday, October 19, 13
  30. Funciones falsamente asíncronas (ej: la anterior :) @gimenete @backbeamio Alberto

    Gimeno function absolute(n, cb) { process.nextTick(function() { if (n >= 0) { return cb(null, n) } cb(null, -n) }) } absolute(-3, function(err, n) { console.log('foo') }) console.log('bar') Saturday, October 19, 13
  31. Funciones falsamente asíncronas (ej: la anterior :) @gimenete @backbeamio Alberto

    Gimeno function absolute(n, cb) { process.nextTick(function() { if (n >= 0) { return cb(null, n) } cb(null, -n) }) } absolute(-3, function(err, n) { console.log('foo') }) console.log('bar') Si quieres usar el callback por lo que sea, mantén el comportamiento usando nextTick() o setInmediate() Saturday, October 19, 13
  32. Lidiando con el asincronismo @gimenete @backbeamio Alberto Gimeno function find(arr,

    cb) { async.each(arr, function(item, next) { if (item > 3) { return cb(null, item) } next() }, function() { return cb(null) }) } Saturday, October 19, 13
  33. Lidiando con el asincronismo @gimenete @backbeamio Alberto Gimeno function find(arr,

    cb) { async.each(arr, function(item, next) { if (item > 3) { return cb(null, item) } next() }, function() { return cb(null) }) } ✗ No hemos llamado a next() y el bucle no termina Saturday, October 19, 13
  34. Organización del código. Problema 1: requires() @gimenete @backbeamio Alberto Gimeno

    var data = require('../core/data') var users = require('../core/users') var log = require('../core/log') var billing = require('../core/billing') var stats = require('../core/stats') Saturday, October 19, 13
  35. Organización del código. Problema 1: requires() @gimenete @backbeamio Alberto Gimeno

    var data = require('../core/data') var users = require('../core/users') var log = require('../core/log') var billing = require('../core/billing') var stats = require('../core/stats') ✗ require() por todas partes Saturday, October 19, 13
  36. Organización del código. Problema 2: arrastrar argumentos @gimenete @backbeamio Alberto

    Gimeno core.data.query(user, project, projectSettings, entity, query, params, callback) Saturday, October 19, 13
  37. Solución @gimenete @backbeamio Alberto Gimeno // index.js exports.init = function()

    { var core = {} core.data = require('./core-data').init(core) core.users = require('./core-users').init(core) core.log = require('./core-log').init(core) core.billing = require('./core-billing').init(core) core.stats = require('./core-stats').init(core) return core } // core-data.js exports.init = function(core) { core.data = {} core.data.list = function() { ... } return core.data } /* uso */ var core = require('./core') core.data.query(...) Saturday, October 19, 13
  38. Solución @gimenete @backbeamio Alberto Gimeno // index.js exports.init = function()

    { var core = {} core.data = require('./core-data').init(core) core.users = require('./core-users').init(core) core.log = require('./core-log').init(core) core.billing = require('./core-billing').init(core) core.stats = require('./core-stats').init(core) return core } // core-data.js exports.init = function(core) { core.data = {} core.data.list = function() { ... } return core.data } /* uso */ var core = require('./core') core.data.query(...) ✓Todos los módulos reciben “core” en su init() Saturday, October 19, 13
  39. Solución @gimenete @backbeamio Alberto Gimeno // index.js exports.init = function()

    { var core = {} core.data = require('./core-data').init(core) core.users = require('./core-users').init(core) core.log = require('./core-log').init(core) core.billing = require('./core-billing').init(core) core.stats = require('./core-stats').init(core) return core } // core-data.js exports.init = function(core) { core.data = {} core.data.list = function() { ... } return core.data } /* uso */ var core = require('./core') core.data.query(...) ✓Todos los módulos reciben “core” en su init() ✓Sólo un require() Saturday, October 19, 13
  40. Integrándolo en express @gimenete @backbeamio Alberto Gimeno app.use(function(req, res, next)

    { req.core = core.init() next() }) app.get('/foo/bar', authenticate, function(req, res) { var core = req.core }) Guardamos “core” en la request Saturday, October 19, 13
  41. Integrándolo en express @gimenete @backbeamio Alberto Gimeno app.use(function(req, res, next)

    { req.core = core.init() next() }) app.get('/foo/bar', authenticate, function(req, res) { var core = req.core }) Guardamos “core” en la request ✓ Podemos acceder en todos los controladores Saturday, October 19, 13
  42. Solución: middleware @gimenete @backbeamio Alberto Gimeno app.use(function(req, res, next) {

    req.core = core.init() res.on('header', function() { // para evitar referencias cíclicas delete req.core }) next() }) app.get('/foo/bar', authenticate, function(req, res) { var core = req.core var user = core.users.current }) Saturday, October 19, 13
  43. Solución: middleware @gimenete @backbeamio Alberto Gimeno app.use(function(req, res, next) {

    req.core = core.init() res.on('header', function() { // para evitar referencias cíclicas delete req.core }) next() }) app.get('/foo/bar', authenticate, function(req, res) { var core = req.core var user = core.users.current }) Sólo necesario si guardamos “req” para evitar referencias cíclicas Saturday, October 19, 13
  44. Solución: middleware @gimenete @backbeamio Alberto Gimeno app.use(function(req, res, next) {

    req.core = core.init() res.on('header', function() { // para evitar referencias cíclicas delete req.core }) next() }) app.get('/foo/bar', authenticate, function(req, res) { var core = req.core var user = core.users.current }) ✓Accedemos al estado sin arrastrar argumentos Sólo necesario si guardamos “req” para evitar referencias cíclicas Saturday, October 19, 13
  45. Resultado @gimenete @backbeamio Alberto Gimeno • El middleware (ej: autenticación)

    tiene acceso al core. • Los controladores llaman a 1 método del core. Saturday, October 19, 13
  46. Resultado @gimenete @backbeamio Alberto Gimeno • El middleware (ej: autenticación)

    tiene acceso al core. • Los controladores llaman a 1 método del core. • El core queda independiente de expressjs. Saturday, October 19, 13
  47. Resultado @gimenete @backbeamio Alberto Gimeno • El middleware (ej: autenticación)

    tiene acceso al core. • Los controladores llaman a 1 método del core. • El core queda independiente de expressjs. • Estructura de directorios Saturday, October 19, 13
  48. Resultado @gimenete @backbeamio Alberto Gimeno • El middleware (ej: autenticación)

    tiene acceso al core. • Los controladores llaman a 1 método del core. • El core queda independiente de expressjs. • Estructura de directorios • core/core-*.js Saturday, October 19, 13
  49. Resultado @gimenete @backbeamio Alberto Gimeno • El middleware (ej: autenticación)

    tiene acceso al core. • Los controladores llaman a 1 método del core. • El core queda independiente de expressjs. • Estructura de directorios • core/core-*.js • web/web-*.js Saturday, October 19, 13
  50. Resultado @gimenete @backbeamio Alberto Gimeno • El middleware (ej: autenticación)

    tiene acceso al core. • Los controladores llaman a 1 método del core. • El core queda independiente de expressjs. • Estructura de directorios • core/core-*.js • web/web-*.js • api/api-*.js Saturday, October 19, 13
  51. Problema: los argumentos siguen creciendo @gimenete @backbeamio Alberto Gimeno core.data.query(entity,

    q, cb) core.data.query(entity, q, params, cb) core.data.query(entity, q, params, limit, offset, cb) /* TypeError: undefined is not a function */ core.data.query('user', 'sort by name', function() { ... }) Saturday, October 19, 13
  52. Problema: los argumentos siguen creciendo @gimenete @backbeamio Alberto Gimeno core.data.query(entity,

    q, cb) core.data.query(entity, q, params, cb) core.data.query(entity, q, params, limit, offset, cb) /* TypeError: undefined is not a function */ core.data.query('user', 'sort by name', function() { ... }) ✗ Si aumentamos los argumentos y no cambiamos todas las llamadas cb = undefined Saturday, October 19, 13
  53. Los argumentos de las callbacks también pueden crecer @gimenete @backbeamio

    Alberto Gimeno cb(err) cb(err, objs, total) cb(err, objs, distances, total) cb(err, objs, distances, total, fromCache) Saturday, October 19, 13
  54. Los argumentos de las callbacks también pueden crecer @gimenete @backbeamio

    Alberto Gimeno Y pueden ser inconsistentes: callbacks parecidos con los argumentos en diferentes posiciones cb(err) cb(err, objs, total) cb(err, objs, distances, total) cb(err, objs, distances, total, fromCache) Saturday, October 19, 13
  55. Solución 1: agrupar argumentos en objetos @gimenete @backbeamio Alberto Gimeno

    // options core.data.query(options, cb) // result cb(err, result) Saturday, October 19, 13
  56. Solución 2: objetos patrón comando @gimenete @backbeamio Alberto Gimeno //

    creamos el objeto var parser = new Parser(str) // configuramos el comportamiento parser.strict = true parser.ignoreComments = true parser.processShebang = true // ejecutamos parser.parse(cb) Saturday, October 19, 13
  57. Solución 3: objetos patrón comando con llamadas encadenadas @gimenete @backbeamio

    Alberto Gimeno core.data.query.list(q, params).run(cb) core.data.query.geo(q, params).limit(100).run(cb) Saturday, October 19, 13
  58. Solución 3: objetos patrón comando con llamadas encadenadas @gimenete @backbeamio

    Alberto Gimeno core.data.query.list(q, params).run(cb) core.data.query.geo(q, params).limit(100).run(cb) list() y geo() devuelven objetos con métodos run() y limit(). limit() devuelve this Saturday, October 19, 13
  59. Excepciones @gimenete @backbeamio Alberto Gimeno • Una excepción no gestionada

    te mata el thread en ejecución Saturday, October 19, 13
  60. Excepciones @gimenete @backbeamio Alberto Gimeno • Una excepción no gestionada

    te mata el thread en ejecución • Pero JavaScript es single-thread... fuck! Saturday, October 19, 13
  61. ¿¿Dos filosofías?? @gimenete @backbeamio Alberto Gimeno 1. Dejar que falle

    y reiniciar el servicio 2. No fallar nunca Saturday, October 19, 13
  62. ¿¿Dos filosofías?? @gimenete @backbeamio Alberto Gimeno 1. Dejar que falle

    y reiniciar el servicio 2. No fallar nunca 3. Mejor no fallar nunca pero estar preparado: forever, monit Saturday, October 19, 13
  63. Capturar errores: uncaughtException @gimenete @backbeamio Alberto Gimeno process.on('uncaughtException', function(err) {

    console.log('Caught exception: ' + err); process.exit(1); }); Saturday, October 19, 13
  64. Capturar errores: uncaughtException @gimenete @backbeamio Alberto Gimeno process.on('uncaughtException', function(err) {

    console.log('Caught exception: ' + err); process.exit(1); }); Usar sólo para notificar el error (log). Termina el proceso ya que An unhandled exception means your application - and by extension node.js itself - is in an undefined state. Blindly resuming means anything could happen. http://nodejs.org/api/process.html#process_event_uncaughtexception Saturday, October 19, 13
  65. Domains (desde node v0.8) @gimenete @backbeamio Alberto Gimeno Domain error

    handlers are not a substitute for closing down your process when an error occurs. http://nodejs.org/api/ domain.html#domain_warning_don_t_ignore_errors ¿En serio? Saturday, October 19, 13
  66. on(‘error’, cb) @gimenete @backbeamio Alberto Gimeno Si no gestionas el

    evento “error” las excepciones son lanzadas (throw) Saturday, October 19, 13
  67. on(‘error’, cb) @gimenete @backbeamio Alberto Gimeno Error: socket hang up

    at createHangUpError (http.js:1360:15) at ServerResponse.OutgoingMessage._writeRaw (http.js:507:26) at ServerResponse.OutgoingMessage._send (http.js:476:15) at ServerResponse.OutgoingMessage.write (http.js:744:12) Si no gestionas el evento “error” las excepciones son lanzadas (throw) Saturday, October 19, 13
  68. @gimenete @backbeamio Alberto Gimeno http.createServer(function (req, res) { req.on('error', errorHandler)

    res.on('error', errorHandler) req.socket.on('error', errorHandler) req.connection.on('error', errorHandler) app(req, res) }) Saturday, October 19, 13
  69. @gimenete @backbeamio Alberto Gimeno No es solución completa: error “max

    listeners”. TODO: añadir listener sólo si no añadido http.createServer(function (req, res) { req.on('error', errorHandler) res.on('error', errorHandler) req.socket.on('error', errorHandler) req.connection.on('error', errorHandler) app(req, res) }) Saturday, October 19, 13
  70. Excepciones: no más try-catch / throw? @gimenete @backbeamio Alberto Gimeno

    • No del todo • JSON.parse() te la puede jugar. Ej: un webservice caído (twitter whale). Pon un try-catch SIEMPRE Saturday, October 19, 13
  71. NPM @gimenete @backbeamio Alberto Gimeno • npm outdated // npmedge

    • npm shrinkwrap Saturday, October 19, 13
  72. NPM @gimenete @backbeamio Alberto Gimeno • npm outdated // npmedge

    • npm shrinkwrap • npm install Saturday, October 19, 13
  73. NPM @gimenete @backbeamio Alberto Gimeno • npm outdated // npmedge

    • npm shrinkwrap • npm install • Qué mola también: mirar el código de los módulos Saturday, October 19, 13
  74. Módulos esenciales @gimenete @backbeamio Alberto Gimeno • async • request

    • underscore • apn, nodemailer, shelljs Saturday, October 19, 13
  75. JavaScript: Meta programación y extensibilidad @gimenete @backbeamio Alberto Gimeno •

    eval() // no es el demonio si se usa bien Saturday, October 19, 13
  76. JavaScript: Meta programación y extensibilidad @gimenete @backbeamio Alberto Gimeno •

    eval() // no es el demonio si se usa bien • new Function() // mejor pero básicamente lo mismo Saturday, October 19, 13
  77. JavaScript: Meta programación y extensibilidad @gimenete @backbeamio Alberto Gimeno •

    eval() // no es el demonio si se usa bien • new Function() // mejor pero básicamente lo mismo • módulo vm // sandboxing Saturday, October 19, 13
  78. ¿JavaScript más rápido que C? @gimenete @backbeamio Alberto Gimeno //

    convertir esto... function parseRow(columns, parser) { var row = {}; for (var i = 0; i < columns.length; i++) { row[columns[i].name] = parser.readColumnValue(); } } // en esto... var code = 'return {\n'; columns.forEach(function(column) { code += '"' + column.name + '":' + 'parser.readColumnValue(),\n'; }); code += '};\n'; var parseRow = new Function('columns', 'parser', code); https://github.com/felixge/faster-than-c Saturday, October 19, 13
  79. Módulo vm: maravillosas posibilidades @gimenete @backbeamio Alberto Gimeno • Haz

    tu app scriptable. hooks? • Ej: imagina hooks directamente en github Saturday, October 19, 13
  80. Módulo vm: maravillosas posibilidades @gimenete @backbeamio Alberto Gimeno • Haz

    tu app scriptable. hooks? • Ej: imagina hooks directamente en github • IFTTT pero en tu propia app (mandar SMS, notificaciones push, lógica condicional,...) Saturday, October 19, 13
  81. Módulo vm: maravillosas posibilidades @gimenete @backbeamio Alberto Gimeno • Haz

    tu app scriptable. hooks? • Ej: imagina hooks directamente en github • IFTTT pero en tu propia app (mandar SMS, notificaciones push, lógica condicional,...) TODO: limitar uso de CPU y evitar bucles infinitos en los scripts Saturday, October 19, 13
  82. Introspecciona tu propia app @gimenete @backbeamio Alberto Gimeno • Módulo

    vm. Ejecuta scripts sin reiniciar Saturday, October 19, 13
  83. Introspecciona tu propia app @gimenete @backbeamio Alberto Gimeno • Módulo

    vm. Ejecuta scripts sin reiniciar • replify https://github.com/dshaw/replify Saturday, October 19, 13
  84. Introspecciona tu propia app @gimenete @backbeamio Alberto Gimeno • Módulo

    vm. Ejecuta scripts sin reiniciar • replify https://github.com/dshaw/replify • Agente Smith Saturday, October 19, 13
  85. Agente smith servidor @gimenete @backbeamio Alberto Gimeno var api =

    { someMethod: function (args, callback) { // ... callback(null, result) } } net.createServer(function (socket) { var agent = new Agent(api) agent.connect(socket, function (err, api) { }) }).listen(1337, function () { console.log("Agent server listening on port 1337") }) Saturday, October 19, 13
  86. Agente smith cliente @gimenete @backbeamio Alberto Gimeno var socket =

    net.connect(1337, function () { var agent = new Agent() agent.connect(socket, function (err, api) { api.someMethod(args, function (err, result) { // ... }) }) }) Saturday, October 19, 13
  87. Multiproceso / multitarea @gimenete @backbeamio Alberto Gimeno • Módulo cluster

    • node-fibers • compute-cluster Saturday, October 19, 13
  88. Multiproceso / multitarea @gimenete @backbeamio Alberto Gimeno • Módulo cluster

    • node-fibers • compute-cluster https://github.com/lloyd/node-compute-cluster Saturday, October 19, 13
  89. Despliegues y multiproceso @gimenete @backbeamio Alberto Gimeno • Módulo cluster

    • Crea un proxy inteligente Saturday, October 19, 13
  90. Despliegues y multiproceso @gimenete @backbeamio Alberto Gimeno • Módulo cluster

    • Crea un proxy inteligente • A partir de http-proxy Saturday, October 19, 13
  91. Despliegues y multiproceso @gimenete @backbeamio Alberto Gimeno • Módulo cluster

    • Crea un proxy inteligente • A partir de http-proxy • ej: SSL en caliente (SNICallback) Saturday, October 19, 13
  92. Despliegues sin downtimes ni dropped connections @gimenete @backbeamio Alberto Gimeno

    1. Proxy “inteligente” con agente smith Saturday, October 19, 13
  93. Despliegues sin downtimes ni dropped connections @gimenete @backbeamio Alberto Gimeno

    1. Proxy “inteligente” con agente smith 2. Lanza instancia Saturday, October 19, 13
  94. Despliegues sin downtimes ni dropped connections @gimenete @backbeamio Alberto Gimeno

    1. Proxy “inteligente” con agente smith 2. Lanza instancia 3. Cuando esté lista conecta al proxy y cambia el puerto Saturday, October 19, 13
  95. Despliegues sin downtimes ni dropped connections @gimenete @backbeamio Alberto Gimeno

    1. Proxy “inteligente” con agente smith 2. Lanza instancia 3. Cuando esté lista conecta al proxy y cambia el puerto 4. Mata la instancia vieja tras 1 minuto Saturday, October 19, 13
  96. Testing y desarrollo @gimenete @backbeamio Alberto Gimeno • Mocha +

    istanbul (mocha-istanbul) para cobertura Saturday, October 19, 13
  97. Testing y desarrollo @gimenete @backbeamio Alberto Gimeno • Mocha +

    istanbul (mocha-istanbul) para cobertura • Haz que tu servicio pueda arrancarse desde un test Saturday, October 19, 13
  98. Testing y desarrollo @gimenete @backbeamio Alberto Gimeno • Mocha +

    istanbul (mocha-istanbul) para cobertura • Haz que tu servicio pueda arrancarse desde un test • require(‘./app’).start(1337) Saturday, October 19, 13
  99. Testing y desarrollo @gimenete @backbeamio Alberto Gimeno • Mocha +

    istanbul (mocha-istanbul) para cobertura • Haz que tu servicio pueda arrancarse desde un test • require(‘./app’).start(1337) • require(‘./app’).stop() Saturday, October 19, 13
  100. Testing y desarrollo @gimenete @backbeamio Alberto Gimeno • Mocha +

    istanbul (mocha-istanbul) para cobertura • Haz que tu servicio pueda arrancarse desde un test • require(‘./app’).start(1337) • require(‘./app’).stop() • Usa process.env.NODE_ENV = ‘production’ / ‘development’ Saturday, October 19, 13
  101. Más recomendaciones sobre Node.js en producción @gimenete @backbeamio Alberto Gimeno

    • node-measured + graphite • logs: bunyan, raygun (servicio externo) Saturday, October 19, 13
  102. Más recomendaciones sobre Node.js en producción @gimenete @backbeamio Alberto Gimeno

    • node-measured + graphite • logs: bunyan, raygun (servicio externo) • node-toobusy Saturday, October 19, 13
  103. Más recomendaciones sobre Node.js en producción @gimenete @backbeamio Alberto Gimeno

    • node-measured + graphite • logs: bunyan, raygun (servicio externo) • node-toobusy https://hacks.mozilla.org/2013/01/building-a-node-js-server-that-wont-melt-a-node-js-holiday-season-part-5/ Building A Node.JS Server That Won’t Melt Saturday, October 19, 13