From 427c155005e575bf387d61dc09d7e99ad282ffb1 Mon Sep 17 00:00:00 2001 From: Lance Ball Date: Tue, 20 Dec 2016 16:15:02 -0500 Subject: [PATCH] feat: Full featured browser capabilities Complete with a full jQuery example. --- examples/jquery/.eslintrc.json | 3 ++ examples/jquery/.gitignore | 1 + examples/jquery/README.md | 11 +++++ examples/jquery/app.js | 68 +++++++++++++++++++++++++++ examples/jquery/index.html | 70 ++++++++++++++++++++++++++++ examples/jquery/index.js | 84 ++++++++++++++++++++++++++++++++++ examples/jquery/package.json | 37 +++++++++++++++ 7 files changed, 274 insertions(+) create mode 100644 examples/jquery/.eslintrc.json create mode 100644 examples/jquery/.gitignore create mode 100644 examples/jquery/README.md create mode 100644 examples/jquery/app.js create mode 100644 examples/jquery/index.html create mode 100644 examples/jquery/index.js create mode 100644 examples/jquery/package.json diff --git a/examples/jquery/.eslintrc.json b/examples/jquery/.eslintrc.json new file mode 100644 index 00000000..97d990dd --- /dev/null +++ b/examples/jquery/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "semistandard" +} \ No newline at end of file diff --git a/examples/jquery/.gitignore b/examples/jquery/.gitignore new file mode 100644 index 00000000..b512c09d --- /dev/null +++ b/examples/jquery/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/examples/jquery/README.md b/examples/jquery/README.md new file mode 100644 index 00000000..e296b232 --- /dev/null +++ b/examples/jquery/README.md @@ -0,0 +1,11 @@ +# JQuery Example + +This example exposes a simple service at the route `http://localhost:3000/flakeyService`. As the service receives requests, it gets slower and slower. Once it takes more than 1 second to respond, the service just returns a `423 (Locked)` error. + +Start the server. + +```sh +$ npm start +``` + +Browse to `http://localhost:3000` and click the button to see the service in action. \ No newline at end of file diff --git a/examples/jquery/app.js b/examples/jquery/app.js new file mode 100644 index 00000000..29b4a855 --- /dev/null +++ b/examples/jquery/app.js @@ -0,0 +1,68 @@ +'use strict'; +/* global $ circuitBreaker */ + +(function appInitialization () { + $(() => { + $('#flakey').click(handleClick('/flakeyService', '#flakeyResponse')); + $('.clear').click(function () { $(this).siblings('p').remove(); }); + }); + + const circuitBreakerOptions = { + timeout: 500, + maxFailures: 2, + resetTimeout: 5000, + Promise: Promise + }; + + function handleClick (route, element) { + const circuit = circuitBreaker((route, element) => { + circuit.fallback(() => ({ body: `${route} unavailable right now. Try later.` })); + + // Return a promise to the circuit + return new Promise((resolve, reject) => { + $.get(route) + .done((data) => resolve(data)) + .fail((err) => { + reject(err); + console.error(err); + }); + }); + }, circuitBreakerOptions); + + circuit.on('success', + (data) => $(element).append(makeNode(`SUCCESS: ${JSON.stringify(data)}`))); + + circuit.on('timeout', + () => $(element).append( + makeNode(`TIMEOUT: ${route} is taking too long to respond.`))); + + circuit.on('reject', + () => $(element).append( + makeNode(`REJECTED: The breaker for ${route} is open. Failing fast.`))); + + circuit.on('open', + () => $(element).append( + makeNode(`OPEN: The breaker for ${route} just opened.`))); + + circuit.on('halfOpen', + () => $(element).append( + makeNode(`HALF_OPEN: The breaker for ${route} is half open.`))); + + circuit.on('close', + () => $(element).append( + makeNode(`CLOSE: The breaker for ${route} has closed. Service OK.`))); + + circuit.on('fallback', + (data) => $(element).append( + makeNode(`FALLBACK: ${JSON.stringify(data)}`))); + + return () => circuit.fire(route, element).catch((e) => console.error(e)); + } + + function makeNode (body) { + const response = document.createElement('p'); + $(response).addClass(body.substring(0, body.indexOf(':')).toLowerCase()); + response.append(body); + return response; + } +})(); diff --git a/examples/jquery/index.html b/examples/jquery/index.html new file mode 100644 index 00000000..15f17eab --- /dev/null +++ b/examples/jquery/index.html @@ -0,0 +1,70 @@ + + + Opossum Circuit Breaker Example + + + + + + +
+

Opossum Circuit Breaker Example

+ +

+ When you click the button here, this simple app calls a flakey web service that takes longer and longer to respond. The app's circuit breaker is configured to timeout after 500ms and execute a fallback command. Every 20 seconds, the flakey service is reset and the pattern is repeated. This should allow you to see all of the various events that occur when using a circuit breaker. +

+

+ The source code for the application is relatively simple, and uses some basic jQuery capabilities to make the ajax calls and update the DOM accordingly. +

+
+ +
+ +
+

FLAKEY RESPONSES

+ Click to clear +
+
+ + diff --git a/examples/jquery/index.js b/examples/jquery/index.js new file mode 100644 index 00000000..543ea43d --- /dev/null +++ b/examples/jquery/index.js @@ -0,0 +1,84 @@ +'use strict'; + +const Hapi = require('hapi'); +const Boom = require('boom'); +const path = require('path'); +const util = require('util'); + +const server = new Hapi.Server(); + +server.connection({ + host: 'localhost', + port: 3000 +}); + +// static file serving +server.register(require('inert', (err) => possibleError(err))); + +[ ['/', path.join(__dirname, 'index.html')], + ['/app.js', path.join(__dirname, 'app.js')], + ['/jquery.js', path.join(__dirname, 'node_modules', 'jquery', 'dist', 'jquery.js')], + ['/opossum.js', path.join(__dirname, '..', '..', 'dist', 'opossum.js')] +].map((entry) => { + server.route({ + method: 'GET', + path: entry[0], + handler: { + file: { + path: entry[1], + confine: false + } + } + }); +}); + +const baseline = 20; +let delay = baseline; +server.route({ + method: 'GET', + path: '/flakeyService', + handler: function flakeyService (request, reply) { + console.log('Flakey service delay', delay); + // if we're really slowing down, just reply with an error + if (delay > 1000) { + console.log('Long delay encountered, returning Error 423 (Locked)'); + return reply( + Boom.locked(util.format({ body: 'Flakey service is flakey' }))); + } + const response = reply({ + body: 'Flakey service response', + delay + }, delay).hold(); + setTimeout(() => { + console.log('Replying with flakey response after delay of', delay); + delay = delay * 2; + response.send(); + }, delay); + } +}); + +// reset the delay every 10 seconds +setInterval(() => { + delay = baseline; + console.log('Resetting flakey service delay to', delay); +}, 20000); + +server.start((err) => { + possibleError(err); + console.log(`Server: ${server.info.uri}`); + console.log('Endpoints:'); + server.table().map((entry) => { + entry.table.map((route) => { + console.log(`${route.method} ${route.path}`); + }); + }); +}); + +process.on('uncaughtException', (e) => { + process._rawDebug(`Caught exception ${e}`); +}); + +function possibleError (err) { + if (err) throw err; +} + diff --git a/examples/jquery/package.json b/examples/jquery/package.json new file mode 100644 index 00000000..e14bc4c2 --- /dev/null +++ b/examples/jquery/package.json @@ -0,0 +1,37 @@ +{ + "name": "opossum-browser-example", + "version": "0.0.1", + "main": "index.js", + "license": "Apache-2.0", + "scripts": { + "lint": "eslint test/*.js index.js app.js", + "start": "node ." + }, + "repository": { + "type": "git", + "url": "git://github.com/bucharest-gold/opossum.git" + }, + "devDependencies": { + "eslint": "~3.8.1", + "eslint-config-semistandard": "~7.0.0", + "eslint-config-standard": "~6.2.0", + "eslint-plugin-promise": "~3.3.0", + "eslint-plugin-react": "~6.4.1", + "eslint-plugin-standard": "~2.0.1" + }, + "description": "Simple example with opossum and browser.", + "dependencies": { + "angular": "^1.6.0", + "angular-route": "^1.6.0", + "boom": "~4.2.0", + "bootstrap": "~3.3.7", + "hapi": "~16.0.1", + "inert": "~4.0.3", + "jquery": "~3.1.1" + }, + "bugs": { + "url": "https://github.com/bucharest-gold/opossum/issues" + }, + "homepage": "https://github.com/bucharest-gold/opossum#readme", + "author": "" +}