From ae0edc3f978d39a399143a1784757315e413287e Mon Sep 17 00:00:00 2001
From: Lloyd Hilaiel <lloyd@hilaiel.com>
Date: Wed, 30 Nov 2011 16:13:31 -0700
Subject: [PATCH] allow verifier to saturate multiple cores.  closes #213

---
 bin/keysigner                    |  3 +-
 bin/verifier                     | 83 ++++++++++++++++++++------------
 lib/verifier/verifier-compute.js | 24 +++++++++
 3 files changed, 78 insertions(+), 32 deletions(-)
 create mode 100644 lib/verifier/verifier-compute.js

diff --git a/bin/keysigner b/bin/keysigner
index a7638a91b..f2235289b 100755
--- a/bin/keysigner
+++ b/bin/keysigner
@@ -113,7 +113,8 @@ app.post('/wsapi/cert_key', validate(["email", "pubkey"]), function(req, resp) {
   }, function (err, r) {
     // consider "application" errors to be the same as harder errors
     if (!err && r && r.error) err = r.error;
-    if (!r || !r.success) err = "no certificate returned from child process";
+    else if (!r || !r.success) err = "no certificate returned from child process";
+
     if (err) {
       logger.error("certification generation error: " + err);
       httputils.serverError(resp, "certification generation error");
diff --git a/bin/verifier b/bin/verifier
index fe4254e55..53584bc0d 100755
--- a/bin/verifier
+++ b/bin/verifier
@@ -42,7 +42,7 @@ path = require('path'),
 url = require('url'),
 fs = require('fs'),
 express = require('express'),
-certassertion = require('../lib/verifier/certassertion.js'),
+computecluster = require('compute-cluster'),
 metrics = require('../lib/metrics'),
 heartbeat = require('../lib/heartbeat'),
 logger = require('../lib/logging').logger,
@@ -78,6 +78,27 @@ if (statsd_config && statsd_config.enabled) {
 
 app.use(express.bodyParser());
 
+try {
+  // explicitly relay VAR_PATH to children
+  process.env['VAR_PATH'] = config.get('var_path');
+
+  // allocate a compute cluster
+  var cc = new computecluster({
+    module: path.join(__dirname, "..", "lib", "verifier", "verifier-compute.js"),
+    max_processes: config.get('max_compute_processes')
+  }).on('error', function(e) {
+    logger.error("error detected in verification computation process!  fatal: " + e.toString());
+    setTimeout(function() { process.exit(1); }, 0);
+  }).on('info', function(msg) {
+    logger.info("(compute cluster): " + msg);
+  }).on('debug', function(msg) {
+    logger.debug("(compute cluster): " + msg);
+  });
+} catch(e) {
+  process.stderr.write("can't allocate compute cluster: " + e + "\n");
+  process.exit(1);
+}
+
 app.post('/verify', function(req, resp, next) {
   req.body = req.body || {}
 
@@ -97,37 +118,35 @@ app.post('/verify', function(req, resp, next) {
     return resp.json({ status: "failure", reason: "need assertion and audience" });
   }
 
-  function doFailure(error) {
-    resp.json({"status":"failure", reason: (error ? error.toString() : "unknown")});
-    metrics.report('verify', {
-      result: 'failure',
-      rp: audience
-    });
-  }
+  cc.enqueue({
+    assertion: assertion,
+    audience: audience
+  }, function (err, r) {
+    // consider "application" errors to be the same as harder errors
+    if (!err && r && r.error) err = r.error;
+    else if (!r || !r.success) err = "no response returned from child process";
+
+    if (err) {
+      resp.json({"status":"failure", reason: err});
+      metrics.report('verify', {
+        result: 'failure',
+        rp: audience
+      });
+    } else {
+      resp.json({
+        status : "okay",
+        email : r.success.email,
+        audience : audience, // NOTE: we return the audience formatted as the RP provided it, not normalized in any way.
+        expires : new Date(r.success.expires).valueOf(),
+        issuer: r.success.issuer
+      });
 
-  try {
-    certassertion.verify(
-      assertion, audience,
-      function(email, audienceFromAssertion, expires, issuer) {
-        resp.json({
-          status : "okay",
-          email : email,
-          audience : audience, // NOTE: we return the audience formatted as the RP provided it, not normalized in any way.
-          expires : expires.valueOf(),
-          issuer: issuer
-        });
-
-        metrics.report('verify', {
-          result: 'success',
-          rp: audienceFromAssertion
-        });
-      },
-      function(error) {
-        doFailure(error);
+      metrics.report('verify', {
+        result: 'success',
+        rp: r.success.audience
       });
-  } catch(e) {
-    doFailure(e);
-  }
+    }
+  });
 });
 
 // shutdown when /code_update is invoked
@@ -141,7 +160,9 @@ app.use(function(req, res,next) {
 });
 
 // shutdown nicely on signals
-shutdown.handleTerminationSignals(app);
+shutdown.handleTerminationSignals(app, function() {
+  cc.exit();
+});
 
 var bindTo = config.get('bind_to');
 app.listen(bindTo.port, bindTo.host, function(conn) {
diff --git a/lib/verifier/verifier-compute.js b/lib/verifier/verifier-compute.js
new file mode 100644
index 000000000..79569252a
--- /dev/null
+++ b/lib/verifier/verifier-compute.js
@@ -0,0 +1,24 @@
+const
+certassertion = require('./certassertion.js');
+
+process.on('message', function(m) {
+  try {
+    certassertion.verify(
+      m.assertion, m.audience,
+      function(email, audienceFromAssertion, expires, issuer) {
+        process.send({
+          success: {
+            email: email,
+            audience: audienceFromAssertion,
+            expires: expires,
+            issuer: issuer
+          }
+        });
+      },
+      function(error) {
+        process.send({error: error});
+      });
+  } catch(e) {
+    process.send({error: e.toString()});
+  }
+});
-- 
GitLab