From 68ebdf8a4ff2154bd202050b6ac98a27bbc59b1b Mon Sep 17 00:00:00 2001 From: Marak Date: Thu, 30 Nov 2017 20:16:46 -0500 Subject: [PATCH] [api] [refactor] Assume no chain by default #39 * Switches default back to end response on exit * Least surprising behavior for users * Is more frequent use-case * Adds configuration options for chaining * Updates examples and tests to new API --- ReadMe.md | 2 ++ examples/express-any-binary.js | 11 ++--------- examples/express-chain-services.js | 9 ++++++--- lib/plugins/spawn/index.js | 18 ++++++++++++++++-- test/service-as-middleware-tests.js | 8 ++++++-- 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index e305055..82f11c2 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -334,6 +334,8 @@ Since `v5.1.0` and above, `microcule` is able to compose multiple functions toge In order to chain multiple services, simply call them as standard Node.js middlewares in the order you want them to execute. +Note: You must specify the `chain` parameter of `spawn()` as `true`, or else microcule will automatically end the response after the first middleware executes. + ```js app.use([logger(), basicAuthHandler, bashServiceHandler, nodeServiceHandlerA, nodeServiceHandlerB], function (req, res) { console.log("No services ended response, made it to end"); diff --git a/examples/express-any-binary.js b/examples/express-any-binary.js index 917d277..0303bab 100644 --- a/examples/express-any-binary.js +++ b/examples/express-any-binary.js @@ -7,17 +7,10 @@ var handler = microcule.plugins.spawn({ argv: ['hello', 'world'] }); -// tail the ReadMe.md file -// any changes to ReadMe.md in root of project will stream to client -/* var handler = microcule.plugins.spawn({ - bin: 'tail', - argv: ['-f', 'ReadMe.md'], - config: { - SERVICE_MAX_TIMEOUT: 60000 - } + bin: 'sh', + argv: ['-c', 'echo "foo" | cat'] }); -*/ // spawn simple ls command to show current directories /* diff --git a/examples/express-chain-services.js b/examples/express-chain-services.js index 08d1bdc..1e3453b 100644 --- a/examples/express-chain-services.js +++ b/examples/express-chain-services.js @@ -19,17 +19,20 @@ var bashService = 'echo "hello bash"' var handlerA = microcule.plugins.spawn({ code: nodeService, - language: "javascript" + language: "javascript", + chain: true }); var handlerB = microcule.plugins.spawn({ code: nodeServiceB, - language: "javascript" + language: "javascript", + chain: true }); var bashHandler = microcule.plugins.spawn({ code: bashService, - language: "bash" + language: "bash", + chain: true }); diff --git a/lib/plugins/spawn/index.js b/lib/plugins/spawn/index.js index 9603eae..0953d32 100644 --- a/lib/plugins/spawn/index.js +++ b/lib/plugins/spawn/index.js @@ -76,10 +76,23 @@ module['exports'] = function spawnService (service) { } */ + // If source code passed in is a JavaScript function in memory, create a small module shim to export the function if (typeof _service.code === "function") { _service.code = "module.exports = " + _service.code.toString(); } + // the default behavior with no additional options is to close the request after first process exits + if (typeof service.endResponseOnExit === 'undefined') { + service.endResponseOnExit = true; + } + + // if the chain option has been set to true, do not endResponseOnExit + // this allows for the processing of several spawned services in sequence without closing the response to the client + // note: "chain" option acts as an alias for endResponseOnExit + if (service.chain === true) { + service.endResponseOnExit = false; + } + // only configure compiled middleware plugin *once* ( same as how all other plugins are configured ) // probably not a good idea to attempt to confifigure compile plugin inside of spawnServiceMiddleware() handler var _compile; @@ -521,7 +534,7 @@ module['exports'] = function spawnService (service) { serviceCompletedTimer = clearTimeout(serviceCompletedTimer); serviceCompleted = true; // dump stderr and perform logging events - status.stderrOutput.forEach(function(e){ + status.stderrOutput.forEach(function (e) { // if the response is erroring, then send errors to stdout ( should still be open ) if (status.erroring === true && service.redirectStderrToStdout) { // send the stderr data to the fd3 handler as an error @@ -536,7 +549,8 @@ module['exports'] = function spawnService (service) { // Note: Only certain languages are currently capable of acting as middlewares // For additional language support, we need an explcit event / API in each language for closing event over pipe3 ( similiar to how javascript services work ) var middlewareEnabledLanguages = ['javascript', 'babel', 'coffee-script']; - if (status.serviceEnded) { + + if ((status.serviceEnded || service.endResponseOnExit === true)) { // If the service has ended ( meaning res.end() was called, or sent via pipe3 message ), // then we will end the response now ( no more middlewares will process) output.end(); diff --git a/test/service-as-middleware-tests.js b/test/service-as-middleware-tests.js index 19c5cce..51810b4 100644 --- a/test/service-as-middleware-tests.js +++ b/test/service-as-middleware-tests.js @@ -15,6 +15,7 @@ test('attempt to create a few chainable microservice spawn handlers', function ( handlers['basicAuth'] = microcule.plugins.spawn({ language: "javascript", + chain: true, code: function (req, res, next) { var auth = require('basic-auth') var credentials = auth(req) @@ -31,10 +32,12 @@ test('attempt to create a few chainable microservice spawn handlers', function ( handlers['write-a'] = microcule.plugins.spawn({ language: "bash", - code: 'echo "a"' + code: 'echo "a"', + chain: true }); handlers['write-b'] = microcule.plugins.spawn({ language: "javascript", + chain: true, code: function (req, res, next) { res.write('b\n'); next(); // call next() to indicate this services is not going to explictly end the response @@ -42,7 +45,8 @@ test('attempt to create a few chainable microservice spawn handlers', function ( }); handlers['write-c'] = microcule.plugins.spawn({ language: "bash", - code: 'echo "c"' + code: 'echo "c"', + chain: true }); t.end(); });