Browse Source

Refactor existing Hapi code

Zane Kansil 10 years ago
parent
commit
6ac1873305

+ 12 - 232
frameworks/JavaScript/hapi/app.js

@@ -1,236 +1,16 @@
-/**
- * Module dependencies.
- */
-
-var cluster = require('cluster'),
-	numCPUs = require('os').cpus().length,
-	Hapi = require('hapi'),
-	Sequelize = require('sequelize'),
-	mongoose = require('mongoose'),
-	conn = mongoose.connect('mongodb://localhost/hello_world'),
-	async = require('async');
-
-var WorldSchema = new mongoose.Schema({
-		id          : Number,
-		randomNumber: Number
-	}, {
-		collection: 'world'
-	}),
-	MWorld = conn.model('World', WorldSchema);
-
-var sequelize = new Sequelize('hello_world', 'benchmarkdbuser', 'benchmarkdbpass', {
-	host: 'localhost',
-	dialect: 'mysql',
-	logging: false
-});
-
-var World = sequelize.define('World', {
-	id: {
-		type: 'Sequelize.INTEGER'
-	},
-	randomNumber: {
-		type: 'Sequelize.INTEGER'
-	}
-}, {
-	timestamps: false,
-	freezeTableName: true
-});
-var Fortune = sequelize.define('Fortune', {
-	id: {
-		type: 'Sequelize.INTEGER'
-	},
-	message: {
-		type: 'Sequelize.STRING'
-	}
-}, {
-	timestamps: false,
-	freezeTableName: true
-});
+var cluster = require('cluster');
+var numCPUs = require('os').cpus().length;
 
 
 if (cluster.isMaster) {
 if (cluster.isMaster) {
-	// Fork workers.
-	for (var i = 0; i < numCPUs; i++) {
-		cluster.fork();
-	}
-
-	cluster.on('exit', function(worker, code, signal) {
-		console.log('worker ' + worker.pid + ' died');
-	});
+  // Fork workers.
+  for (var i = 0; i < numCPUs; i++) {
+    cluster.fork();
+  }
+
+  cluster.on('exit', function (worker, code, signal) {
+    process.exit(1);
+  });
 } else {
 } else {
-	var server = module.exports = new Hapi.Server();
-	server.connection({port: 8080});
-	server.views({
-		engines: {
-			html: require('handlebars')
-		},
-		path: __dirname + '/views'
-	});
-
-	server.route({
-		method: 'GET',
-		path: '/json',
-		handler: function(req, reply) {
-			reply({ message: 'Hello, World!' }).header('Server', 'hapi');
-		}
-	});
-
-	server.route({
-		method: 'GET',
-		path: '/plaintext',
-		handler: function(req, reply) {
-			reply('Hello, World!')
-			 .header('Server', 'hapi')
-			 .header('Content-Type', 'text/plain');
-		}
-	});
-
-	server.route({
-		method: 'GET',
-		path: '/mongoose/{queries?}',
-		handler: function(req, reply){
-			var queries = isNaN(req.params.queries) ? 1 : parseInt(req.params.queries, 10),
-				queryFunctions = [];
-
-			queries = Math.min(Math.max(queries, 1), 500);
-
-			for (var i = 1; i <= queries; i++) {
-				queryFunctions.push(function(callback){
-					MWorld.findOne({ id: (Math.floor(Math.random() * 10000) + 1) }).exec(callback);
-				});
-			}
-
-			async.parallel(queryFunctions, function(err, results){
-				if (!req.params.queries) {
-					results = results[0];
-				}
-				reply(results).header('Server', 'hapi');
-			});
-		}
-	});
-
-	server.route({
-		method: 'GET',
-		path: '/mysql-orm/{queries?}',
-		handler: function(req, reply){
-			var queries = isNaN(req.params.queries) ? 1 : parseInt(req.params.queries, 10),
-				queryFunctions = [];
-
-			queries = Math.min(Math.max(queries, 1), 500);
-
-			for (var i = 1; i <= queries; i++) {
-				queryFunctions.push(function(callback){
-					World.findOne({
-						where: {
-							id: Math.floor(Math.random() * 10000) + 1}
-						}
-					).complete(callback);
-				});
-			}
-
-			async.parallel(queryFunctions, function(err, results){
-				if (!req.params.queries) {
-					results = results[0];
-				}
-				reply(results).header('Server', 'hapi');
-			});
-		}
-	});
-
-	server.route({
-		method: 'GET',
-		path: '/fortune',
-		handler: function(req,reply){
-			Fortune.findAll().complete(function(err, fortunes){
-				fortunes.push({
-					id: 0,
-					message: 'Additional fortune added at request time.'
-				});
-				fortunes.sort(function(a, b){
-					return (a.message < b.message) ? -1 : 1;
-				});
-
-				reply.view('fortunes', {
-					fortunes: fortunes
-				}).header('Server', 'hapi');
-			});
-		}
-	});
-
-	server.route({
-		method: 'GET',
-		path: '/mongoose-update/{queries?}',
-		handler: function(req, reply){
-			var queries = isNaN(req.params.queries) ? 1 : parseInt(req.params.queries, 10),
-				selectFunctions = [];
-
-			queries = Math.max(Math.min(queries, 500), 1);
-
-			for (var i = 1; i <= queries; i++) {
-				selectFunctions.push(function(callback){
-					MWorld.findOne({ id: Math.floor(Math.random() * 10000) + 1 }).exec(callback);
-				});
-			}
-
-			async.parallel(selectFunctions, function(err, worlds) {
-				var updateFunctions = [];
-
-				for (var i = 0; i < queries; i++) {
-					(function(i){
-						updateFunctions.push(function(callback){
-							worlds[i].randomNumber = Math.ceil(Math.random() * 10000);
-							MWorld.update({
-								id: worlds[i]
-							}, {
-								randomNumber: worlds[i].randomNumber
-							}, callback);
-						});
-					})(i);
-				}
-
-				async.parallel(updateFunctions, function(err, updates) {
-					reply(worlds).header('Server', 'hapi');
-				});
-			});
-		}		
-	});
-
-	server.route({
-		method: 'GET',
-		path: '/mysql-orm-update/{queries?}',
-		handler: function(req,reply){
-			var queries = isNaN(req.params.queries) ? 1 : parseInt(req.params.queries, 10),
-				selectFunctions = [];
-
-			queries = Math.max(Math.min(queries, 500), 1);
-
-			for (var i = 1; i <= queries; i++) {
-				selectFunctions.push(function(callback){
-					World.findOne({
-						where: {
-							id: Math.floor(Math.random() * 10000) + 1}
-						}
-					).complete(callback);
-				});
-			}
-
-			async.parallel(selectFunctions, function(err, worlds) {
-				var updateFunctions = [];
-
-				for (var i = 0; i < queries; i++) {
-					(function(i){
-						updateFunctions.push(function(callback){
-							worlds[i].randomNumber = Math.ceil(Math.random() * 10000);
-							worlds[i].save().complete(callback);
-						});
-					})(i);
-				}
-
-				async.parallel(updateFunctions, function(err, updates) {
-					reply(worlds).header('Server', 'hapi');
-				});
-			});
-		}
-	});
-
-	server.start();
+  // worker task
+  require('./create-server');
 }
 }

+ 10 - 9
frameworks/JavaScript/hapi/benchmark_config.json

@@ -22,16 +22,17 @@
     },
     },
     "mongodb": {
     "mongodb": {
       "setup_file": "setup",
       "setup_file": "setup",
-      "db_url": "/mongoose/",
-      "query_url": "/mongoose/",
-      "update_url": "/mongoose-update/",
+      "db_url": "/mongoose/db",
+      "query_url": "/mongoose/queries?queries=",
+      "fortune_url": "/mongoose/fortunes",
+      "update_url": "/mongoose/updates?queries=",
       "port": 8080,
       "port": 8080,
       "approach": "Realistic",
       "approach": "Realistic",
       "classification": "Micro",
       "classification": "Micro",
       "database": "MongoDB",
       "database": "MongoDB",
       "framework": "hapi",
       "framework": "hapi",
       "language": "JavaScript",
       "language": "JavaScript",
-      "orm": "Raw",
+      "orm": "Full",
       "platform": "nodejs",
       "platform": "nodejs",
       "webserver": "None",
       "webserver": "None",
       "os": "Linux",
       "os": "Linux",
@@ -42,17 +43,17 @@
     },
     },
     "mysql": {
     "mysql": {
       "setup_file": "setup",
       "setup_file": "setup",
-      "db_url": "/mysql-orm/",
-      "query_url": "/mysql-orm/",
-      "fortune_url": "/fortune",
-      "update_url": "/mysql-orm-update/",
+      "db_url": "/sequelize/db",
+      "query_url": "/sequelize/queries?queries=",
+      "fortune_url": "/sequelize/fortunes",
+      "update_url": "/sequelize/updates?queries=",
       "port": 8080,
       "port": 8080,
       "approach": "Realistic",
       "approach": "Realistic",
       "classification": "Micro",
       "classification": "Micro",
       "database": "MySQL",
       "database": "MySQL",
       "framework": "hapi",
       "framework": "hapi",
       "language": "JavaScript",
       "language": "JavaScript",
-      "orm": "Raw",
+      "orm": "Full",
       "platform": "nodejs",
       "platform": "nodejs",
       "webserver": "None",
       "webserver": "None",
       "os": "Linux",
       "os": "Linux",

+ 50 - 0
frameworks/JavaScript/hapi/create-server.js

@@ -0,0 +1,50 @@
+var Hapi = require('hapi');
+var server = new Hapi.Server();
+server.connection({port: 8080});
+server.views({
+  engines: {
+    hbs: require('handlebars')
+  },
+  path: __dirname + '/views',
+  compileOptions: {
+    pretty: false
+  }
+});
+
+var MongooseHandler = require('./handlers/mongoose');
+var SequelizeHandler = require('./handlers/sequelize');
+
+Route('/json', JsonSerialization);
+Route('/plaintext', Plaintext);
+
+Route('/mongoose/db', MongooseHandler.SingleQuery);
+Route('/mongoose/queries', MongooseHandler.MultipleQueries);
+Route('/mongoose/fortunes', MongooseHandler.Fortunes);
+Route('/mongoose/updates', MongooseHandler.Updates);
+
+Route('/sequelize/db', SequelizeHandler.SingleQuery);
+Route('/sequelize/queries', SequelizeHandler.MultipleQueries);
+Route('/sequelize/fortunes', SequelizeHandler.Fortunes);
+Route('/sequelize/updates', SequelizeHandler.Updates);
+
+function JsonSerialization(req, reply) {
+  reply({ message: 'Hello, World!' })
+    .header('Server', 'hapi');
+}
+
+function Plaintext(req, reply) {
+  reply('Hello, World!')
+    .header('Server', 'hapi')
+    .header('Content-Type', 'text/plain');
+}
+
+// Makes routing simpler as tfb routes are all GET's
+// We also don't use the nifty route features that Hapi has
+// to offer such as attaching a validator
+function Route(path, handler) {
+  server.route({ method: 'GET', path: path, handler: handler})
+}
+
+server.start(function (err) {
+  console.log('Hapi worker started and listening on ' + server.info.uri);
+});

+ 107 - 0
frameworks/JavaScript/hapi/handlers/mongoose.js

@@ -0,0 +1,107 @@
+// Connects to MongoDB using the mongoose driver
+// Handles related routes
+
+var h = require('../helper');
+var Mongoose = require('mongoose');
+var async = require('async');
+var connection = Mongoose.connect('mongodb://127.0.0.1/hello_world');
+
+var WorldSchema = new Mongoose.Schema({
+    id :          Number,
+    randomNumber: Number
+  }, {
+    collection: 'world'
+  });
+var FortuneSchema = new Mongoose.Schema({
+    id:      Number,
+    message: String
+  }, {
+    collection: 'fortune'
+  });
+
+var Worlds = connection.model('World', WorldSchema);
+var Fortunes = connection.model('Fortune', FortuneSchema);
+
+function mongooseRandomWorld(callback) {
+  Worlds.findOne({
+    id: h.randomTfbNumber()
+  }).exec(callback);
+}
+
+function mongooseGetAllFortunes(callback) {
+  Fortunes.find({})
+    .exec(callback);
+}
+
+module.exports = {
+
+  SingleQuery: function(req, reply) {
+    mongooseRandomWorld(function (err, world) {
+      if (err) { return process.exit(1); }
+
+      reply(world)
+        .header('Server', 'hapi');
+    });
+  },
+
+  MultipleQueries: function(req, reply) {
+    var queries = h.getQueries(req);
+    var worldsToGet = h.fillArray(mongooseRandomWorld, queries);
+
+    async.parallel(worldsToGet, function (err, worlds) {
+      if (err) { return process.exit(1); }
+
+      reply(worlds)
+        .header('Server', 'hapi');
+    });
+  },
+
+  Fortunes: function(req, reply) {
+    mongooseGetAllFortunes(function (err, fortunes) {
+      if (err) { return process.exit(1); }
+
+      fortunes.push(h.ADDITIONAL_FORTUNE);
+      fortunes.sort(function (a, b) {
+        return a.message.localeCompare(b.message);
+      });
+      
+      reply.view('fortunes', {
+        fortunes: fortunes
+      })
+        .header('Content-Type', 'text/html')
+        .header('Server', 'hapi');
+    });
+  },
+
+  Updates: function(req, reply) {
+    var queries = h.getQueries(req);
+    var worldsToGet = h.fillArray(mongooseRandomWorld, queries);
+
+    async.parallel(worldsToGet, function (err, worlds) {
+      if (err) { return process.exit(1); }
+
+      var updateFunctions = []
+
+      for (var i = 0; i < queries; i++) {
+        (function (i) {
+          updateFunctions.push(function (callback) {
+            worlds[i].randomNumber = h.randomTfbNumber();
+            Worlds.update({
+              id: worlds[i].id
+            }, {
+              randomNumber: worlds[i].randomNumber
+            }, callback);
+          });
+        }(i));
+      }
+
+      async.parallel(updateFunctions, function (err, results) {
+        if (err) { return process.exit(1); }
+
+        reply(worlds)
+          .header('Server', 'hapi');
+      });
+    });
+  }
+
+};

+ 113 - 0
frameworks/JavaScript/hapi/handlers/sequelize.js

@@ -0,0 +1,113 @@
+var h = require('../helper');
+var Promise = require('bluebird');
+
+var Sequelize = require('sequelize');
+var sequelize = new Sequelize('hello_world', 'benchmarkdbuser', 'benchmarkdbpass', {
+  host: '127.0.0.1',
+  dialect: 'mysql',
+  logging: false
+});
+
+var Worlds = sequelize.define('World', {
+  id:           { type: 'Sequelize.INTEGER' },
+  randomNumber: { type: 'Sequelize.INTEGER' }
+}, {
+  timestamps: false,
+  freezeTableName: true
+});
+
+var Fortunes = sequelize.define('Fortune', {
+  id:           { type: 'Sequelize.INTEGER' },
+  message:      { type: 'Sequelize.STRING' }
+}, {
+  timestamps: false,
+  freezeTableName: true
+});
+
+var randomWorldPromise = function() {
+  return Worlds.findOne({
+    where: { id: h.randomTfbNumber() }
+  }).then(function (results) {
+    return results;
+  }).catch(function (err) {
+    process.exit(1);
+  });
+}
+
+module.exports = {
+
+  SingleQuery: function (req, reply) {
+    randomWorldPromise().then(function (world) {
+      reply(world)
+        .header('Server', 'hapi');
+    })
+  },
+
+  MultipleQueries: function (req, reply) {
+    var queries = h.getQueries(req);
+    var worldPromises = [];
+
+    for (var i = 0; i < queries; i++) {
+      worldPromises.push(randomWorldPromise());
+    }
+
+    Promise.all(worldPromises).then(function (worlds) {
+      reply(worlds)
+        .header('Server', 'hapi');
+    });
+  },
+
+  Fortunes: function (req, reply) {
+    Fortunes.findAll().then(function (fortunes) {
+      fortunes.push(h.ADDITIONAL_FORTUNE);
+      fortunes.sort(function (a, b) {
+        return a.message.localeCompare(b.message);
+      });
+
+      reply.view('fortunes', {
+        fortunes: fortunes
+      })
+        .header('Content-Type', 'text/html')
+        .header('Server', 'hapi');
+    }).catch(function (err) {
+      process.exit(1);
+    }); 
+  },
+
+  Updates: function (req, reply) {
+    var queries = h.getQueries(req);
+    var worldPromises = [];
+
+    for (var i = 0; i < queries; i++) {
+      worldPromises.push(randomWorldPromise());
+    }
+
+    var worldUpdate = function (world) {
+      world.randomNumber = h.randomTfbNumber();
+
+      return Worlds.update(
+          { randomNumber: world.randomNumber },
+          { where: { id: world.id } }
+        )
+        .then(function (results) {
+            return world;
+          })
+        .catch(function (err) {
+            process.exit(1);
+          });
+    }
+
+    Promise
+      .all(worldPromises)
+      .map(function (world) {
+        return worldUpdate(world);
+      })
+      .then(function (updated) {
+        reply(updated)
+          .header('Server', 'hapi')
+      })
+      .catch(function (e) {
+        process.exit(1);
+      });
+  }
+}

+ 31 - 0
frameworks/JavaScript/hapi/helper.js

@@ -0,0 +1,31 @@
+var Handlebars = require('handlebars');
+
+var GREETING = "Hello, World";
+var HELLO_OBJ = { message: GREETING }
+
+module.exports = {
+  randomTfbNumber: function() {
+    return Math.floor(Math.random() * 10000) + 1;
+  },
+
+  fillArray: function(value, len) {
+    var filled = [];
+
+    for (var i = 0; i < len; i++) {
+      filled.push(value);
+    }
+    return filled;
+  },
+
+  getQueries: function(req) {
+    var queries = ~~(req.query.queries) || 1;
+    queries = Math.min(Math.max(queries, 1), 500);
+    return queries;
+  },
+
+  ADDITIONAL_FORTUNE: {
+    id: 0,
+    message: 'Additional fortune added at request time.'
+  }
+
+}

+ 12 - 11
frameworks/JavaScript/hapi/package.json

@@ -1,13 +1,14 @@
 {
 {
-	"name": "application-name",
-	"version": "0.0.1",
-	"private": true,
-	"dependencies": {
-		"hapi": "8.4.0",
-		"mongoose": "4.0.1",
-		"async": "0.9.0",
-		"handlebars": "3.0.1",
-		"sequelize": "2.0.6",
-		"mysql": "2.6.2"
-	}
+  "name": "application-name",
+  "version": "0.0.1",
+  "private": true,
+  "dependencies": {
+    "async": "1.2.0",
+    "bluebird": "^2.9.27",
+    "handlebars": "3.0.3",
+    "hapi": "8.6.0",
+    "mongoose": "4.0.4",
+    "mysql": "2.7.0",
+    "sequelize": "3.1.1"
+  }
 }
 }

+ 1 - 0
frameworks/JavaScript/hapi/views/fortunes.hbs

@@ -0,0 +1 @@
+<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>{{#fortunes}}<tr><td>{{id}}</td><td>{{message}}</td></tr>{{/fortunes}}</table></body></html>

+ 0 - 21
frameworks/JavaScript/hapi/views/fortunes.html

@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-	<title>Fortunes</title>
-</head>
-
-<body>
-	<table>
-		<tr>
-			<th>id</th>
-			<th>message</th>
-		</tr>
-{{#fortunes}}
-		<tr>
-			<td>{{id}}</td>
-			<td>{{message}}</td>
-		</tr>
-{{/fortunes}}
-	</table>
-</body>
-</html>