Skip to content

Commit

Permalink
feat: Full featured browser capabilities
Browse files Browse the repository at this point in the history
Complete with a full jQuery example.
  • Loading branch information
lance committed Dec 22, 2016
1 parent d4496d8 commit 2cc08f0
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 0 deletions.
3 changes: 3 additions & 0 deletions examples/jquery/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "semistandard"
}
1 change: 1 addition & 0 deletions examples/jquery/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
11 changes: 11 additions & 0 deletions examples/jquery/README.md
Original file line number Diff line number Diff line change
@@ -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.
68 changes: 68 additions & 0 deletions examples/jquery/app.js
Original file line number Diff line number Diff line change
@@ -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;
}
})();
70 changes: 70 additions & 0 deletions examples/jquery/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<html>
<head>
<title>Opossum Circuit Breaker Example</title>
<script type='text/javascript' src="/jquery.js"></script>
<script type='text/javascript' src="/opossum.js"></script>
<script type='text/javascript' src="/app.js"></script>
<style>
body {
font-family: Arial, Helvetica, sans-serif;
margin: 1em;
}
button {
padding: 1ex 1em;
margin-right: 1em;
font-size: larger;
}
.row {
padding: 1em;
width: 100%
}
h2 {
border-bottom: 1px dotted #999;
}
.clear {
cursor: pointer;
color: #3336ff;
}
.success {
color: darkgreen
}
.open {
color: red
}
.fallback {
color: darkblue
}
.rejected {
color: darkorange
}
.close {
color: green
}
.timeout {
color: darksalmon
}
</style>
</head>
<body>
<div>
<h1>Opossum Circuit Breaker Example</h1>

<p>
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.
</p>
<p>
The <a href="/app.js">source code</a> for the application is relatively simple, and uses some basic jQuery capabilities to make the ajax calls and update the DOM accordingly.
</p>
<div class="row">
<button type="button" id="flakey">
Flakey Service
</button>
</div>

<div class="row" id="flakeyResponse">
<h2>FLAKEY RESPONSES</h2>
<span class="clear">Click to clear</span>
</div>
</div>
</body>
</html>
84 changes: 84 additions & 0 deletions examples/jquery/index.js
Original file line number Diff line number Diff line change
@@ -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;
}

37 changes: 37 additions & 0 deletions examples/jquery/package.json
Original file line number Diff line number Diff line change
@@ -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": ""
}

0 comments on commit 2cc08f0

Please sign in to comment.