Rechercher

Ce contenu n'est pas disponible dans la langue sélectionnée.

Chapter 3. Example application using the circuit breaker add-on

download PDF

You can use the circuit breaker add-on to implement a circuit breaker pattern in your Node.js applications. This example shows how to use the circuit breaker add-on to report the failure of a remote service and to limit access to the failed service until it becomes available to handle requests.

3.1. Overview of the example application

This example application consists of two microservices:

greeting-service
This is the entry point to the application. A web client calls greeting-service to request a greeting. greeting-service then sends a request that is wrapped in a circuit breaker object to the remote name-service.
name-service
name-service receives the request from greeting-service. The web client interface contains a toggle button that you can click to simulate the availability or failure of the remote name-service. If the toggle button is currently set to on, name-service sends a response to complete the greeting. However, if the toggle button is currently set to off, name-service sends an error to indicate that the service is currently unavailable.

3.2. Example greeting-service

greeting-service imports the circuit breaker add-on. greeting-service protects calls to the remote name-service by wrapping these calls in a circuit breaker object.

greeting-service exposes the following endpoints:

  • The /api/greeting endpoint receives a call from the web client that requests a greeting. The /api/greeting endpoint sends a call to the /api/name endpoint in the remote name-service as part of processing the client request. The call to the /api/name endpoint is wrapped in a circuit breaker object. If the remote name-service is currently available, the /api/greeting endpoint sends a greeting to the client. However, if the remote name-service is currently unavailable, the /api/greeting endpoint sends an error response to the client.
  • The /api/cb-state endpoint returns the current state of the circuit breaker. If this is set to open, the circuit breaker is currently preventing requests from reaching the failed service. If this is set to closed, the circuit breaker is currently allowing requests to reach the service.

The following code example shows how to develop greeting-service:

'use strict';
const path = require('path');
const http = require('http');
const express = require('express');
const bodyParser = require('body-parser');

// Import the circuit breaker add-on
const Opossum = require('@redhat/opossum');

const probe = require('kube-probe');
const nameService = require('./lib/name-service-client');

const app = express();
const server = http.createServer(app);

// Add basic health check endpoints
probe(app);

const nameServiceHost = process.env.NAME_SERVICE_HOST || 'http://nodejs-circuit-breaker-redhat-name:8080';

// Set some circuit breaker options
const circuitOptions = {
  timeout: 3000, // If name service takes longer than 0.3 seconds,
                 // trigger a failure
  errorThresholdPercentage: 50, // When 50% of requests fail,
                                // trip the circuit
  resetTimeout: 10000 // After 10 seconds, try again.
};

// Create a new circuit breaker instance and pass the remote nameService
// as its first parameter
const circuit = new Opossum(nameService, circuitOptions);

// Create the app with an initial websocket endpoint
require('./lib/web-socket')(server, circuit);

// Serve index.html from the file system
app.use(express.static(path.join(__dirname, 'public')));
// Expose the license.html at http[s]://[host]:[port]/licences/licenses.html
app.use('/licenses', express.static(path.join(__dirname, 'licenses')));

// Send and receive json
app.use(bodyParser.json());

// Greeting API
app.get('/api/greeting', (request, response) => {
  // Use the circuit breaker’s fire method to execute the call
  // to the name service
  circuit.fire(`${nameServiceHost}/api/name`).then(name => {
    response.send({ content: `Hello, ${name}`, time: new Date() });
  }).catch(console.error);
});

// Circuit breaker state API
app.get('/api/cb-state', (request, response) => {
  response.send({ state: circuit.opened ? 'open' : 'closed' });
});

app.get('/api/name-service-host', (request, response) => {
  response.send({ host: nameServiceHost });
});

module.exports = server;

3.3. Example name-service

name-service exposes the following endpoints:

  • The /api/name endpoint receives a call from greeting-service. If name-service is currently available, the /api/name endpoint sends a World! response to complete the greeting. However, if name-service is currently unavailable, the /api/name endpoint sends a Name service down error with an HTTP status code of 500.
  • The /api/state endpoint controls the current behavior of the /api/name endpoint. It determines whether the service sends a response or fails with an error message.

The following code example shows how to develop name-service:

'use strict';

const path = require('path');
const http = require('http');
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const probe = require('kube-probe');

const app = express();
const server = http.createServer(app);

// Adds basic health-check endpoints
probe(app);

let isOn = true;
const { update, sendMessage } = require('./lib/web-socket')(server, _ => isOn);

// Send and receive json
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

// CORS support
app.use(cors());

// Name service API
app.get('/api/name', (request, response) => {
  if (isOn) {
    response.send('World!');
  } else {
    response.status(500).send('Name service down');
  }
  sendMessage(`${new Date()} ${isOn ? 'OK' : 'FAIL'}`);
});

// Current state of service
app.put('/api/state', (request, response) => {
  isOn = request.body.state === 'ok';
  response.send({ state: isOn });
  update();
});

app.get('/api/info',
  (request, response) => response.send({ state: isOn ? 'ok' : 'fail' }));

// Expose the license.html at http[s]://[host]:[port]/licenses/licenses.html
app.use('/licenses', express.static(path.join(__dirname, 'licenses')));

module.exports = server;

Additional resources

Red Hat logoGithubRedditYoutubeTwitter

Apprendre

Essayez, achetez et vendez

Communautés

À propos de la documentation Red Hat

Nous aidons les utilisateurs de Red Hat à innover et à atteindre leurs objectifs grâce à nos produits et services avec un contenu auquel ils peuvent faire confiance.

Rendre l’open source plus inclusif

Red Hat s'engage à remplacer le langage problématique dans notre code, notre documentation et nos propriétés Web. Pour plus de détails, consultez leBlog Red Hat.

À propos de Red Hat

Nous proposons des solutions renforcées qui facilitent le travail des entreprises sur plusieurs plates-formes et environnements, du centre de données central à la périphérie du réseau.

© 2024 Red Hat, Inc.