express-http-proxy icon indicating copy to clipboard operation
express-http-proxy copied to clipboard

[Perhaps] support Cirquit Breaker for proxy requests

Open SimonPNorra opened this issue 7 years ago • 4 comments

Hey there,

we are currently using your library to route requests to a third party service. I was wondering if we can use a ciquit breaker implementation like histrixjs with your library (https://www.npmjs.com/package/hystrixjs). Common implementations of cirquit breaker are wrapping promises and are not compatible with middlewares. If there is already a hook we can use (and unfortunately I don't see it), can you please help me and give a hint how to solve it?

Big thanks in advance.

Simon

SimonPNorra avatar May 15 '17 13:05 SimonPNorra

Hi @SimonPNorra

I haven't worked with any circuit breaker implementations yet. Sounds interesting, can you elaborate on what you'd need express-http-proxy to do in order to support you?

Thanks

monkpow avatar May 31 '17 16:05 monkpow

Hi @monkpow

Thanks for your reply. We are using express-http-proxy in a microservice environment and do route some requests from our express server to other services, like a central validation service. Requests to this service are handled realtime and the response is providing feedback to our client. We have a behavior implemented, when this validation service isn't available anymore. We believe that it optimizes experience and resilience of our system when not each request runs in timeouts if the service is temporary not available.

A cirquit breaker implementation could help to allow only a given threshold of requests running in a timeout and handling further possible failures directly in the proxy, by opening the cirquit. After a given time the cirquit breaker would close again to test the connectivity. Based on the result the cirquit would kept closed our get open again.

My question was just, if you could help us to integrate an already existing cirquit breaker implementation into your proxy implementation. Otherwise if you would like to make your own, I would be very fine with this as well. :) Martin Fowler wrote a very nice article about cirquit breaker and their implementation: https://martinfowler.com/bliki/CircuitBreaker.html

Big thanks, Simon

SimonPNorra avatar Jun 02 '17 06:06 SimonPNorra

Hello @monkpow . I'm trying to implement a circuit breaker with opossum around a proxy request. Is this feature available or still under dev?

RobertoMSousa avatar Feb 12 '20 14:02 RobertoMSousa

I'm using express-http-proxy with opossum, a circuit breaker lib. I managed to integrate express-http-proxy with a circuit breaker adding a new option circuitBreaker:

//index.js

//==> circuitBreaker option is a function that expects two params: sendProxyRequest and container
//==> if circuitBreaker is undefined, then it just execute sendProxyRequest function.
function defineCircuitBreaker(userOptions) {
  if (userOptions && userOptions.circuitBreaker) {
    return userOptions.circuitBreaker;
  } else {
    return function (fn, container) { return fn(container); };
  }
}

module.exports = function proxy(host, userOptions) {
  assert(host, 'Host should not be empty');

  return function handleProxy(req, res, next) {
    debug('[start proxy] ' + req.path);
    var container = new ScopeContainer(req, res, next, host, userOptions);
    var circuitBreaker = defineCircuitBreaker(userOptions);

    filterUserRequest(container)
      .then(buildProxyReq)
      .then(resolveProxyHost)
      .then(decorateProxyReqOpts)
      .then(resolveProxyReqPath)
      .then(decorateProxyReqBody)
      .then(prepareProxyReq)
      //========> here's the change <========
      .then((container) => circuitBreaker(sendProxyRequest, container))
      //========> here's the change <========
      .then(maybeSkipToNextHandler)
      .then(copyProxyResHeadersToUserRes)
      .then(decorateUserResHeaders)
      .then(decorateUserRes)
      .then(sendUserRes)
      .catch(function (err) {
        // I sometimes reject without an error to shortcircuit the remaining
        // steps and return control to the host application.

        if (err) {
          var resolver = (container.options.proxyErrorHandler) ?
            container.options.proxyErrorHandler :
            handleProxyErrors;
          resolver(err, res, next);
        } else {
          next();
        }
      });
  };
};

Since circuitBreak is a function, it's flexible for any(or almost) circuit-break lib, not only for opossum. The following code is a example with opossum:

const router = require('express').Router();
const proxy = require('express-http-proxy-circuit-breaker');
const CircuitBreaker = require('opossum');
const addCircuitBreaker = function(requestFn, container) {
    const breaker = new CircuitBreaker(requestFn, {
        timeout: 3000, // If our function takes longer than 3 seconds, trigger a failure
        errorThresholdPercentage: 50, // When 50% of requests fail, trip the circuit
        resetTimeout: 30000, // After 30 seconds, try again.
    });
    return breaker.fire(container);
};

router.use('*', proxy('service-endpoint', {
    ... //other proxy options here
    circuitBreaker: addCircuitBreaker
}));

I would like to get some feedback before open a PR.

danilosampaio avatar Jun 16 '21 20:06 danilosampaio