h2non / rocky

Full-featured, middleware-oriented, programmatic HTTP and WebSocket proxy for node.js (deprecated)
MIT License
371 stars 24 forks source link

Forcing a retry in response middleware #82

Closed kacperzuk closed 8 years ago

kacperzuk commented 8 years ago

Is it possible to force a retry from middleware? For example with this code:

const proxy = require("rocky")();
const http = require("http");

proxy
  .get("/")
  .retry()
  .balance(["http://127.0.0.1:3001", "http://127.0.0.1:3002"])
  .useResponse((req, res, next) => {
    let body = JSON.parse(res.body);
    if(body.status !== "ok") {
      // somehow force a retry here to get response from second server
    }

    next();
  });
proxy.listen(3000);

// broken target server
http.createServer((req, res) => {
  res.write(JSON.stringify({ status: 'error' }));
  res.end();
}).listen(3001);
// working target server
http.createServer((req, res) => {
  res.write(JSON.stringify({ status: 'ok' }));
  res.end();
}).listen(3002);

I'd like it to always return ok to client:

> curl localhost:3000
{"status":"ok"}
> curl localhost:3000
{"status":"ok"}
h2non commented 8 years ago

Use the retry/backoff settings to enable it. You can dinamically enable it, but from the request middleware instead of the response. See examples/retry.js

kacperzuk commented 8 years ago

Oh, okay, it were custom retry strategies that I've missed :).

One more question, I hope it's the last one: is it possible to make retries try other servers too when using balance? I've tried this: http://pastebin.com/eVJSWMEt, but retries are always made to the same server as on the first try. So half requests fail, even though there's balancing and retry/backoff configured.

h2non commented 8 years ago

I see what you're looking for, which is similar to what I've implemented for resilient.js.

The following code should be functional, but rely on mutation which is not too great, however it does the job. Give it a try!

const proxy = require("rocky")();
const http = require("http");

// configuration
proxy
  .get("*")
  .retry({ retries: 3 })
  .balance(["http://127.0.0.1:9999", "http://127.0.0.1:3001"])

proxy.listen(3000);

// debug info
proxy.on('proxy:retry', (err, req, res) => {
  const opts = req.rocky.options
  opts.target = opts.balance[0]
  console.log('Retrying to next target:', opts.target)
})

// working server
http.createServer(function (req, res) {
  res.writeHead(200);
  res.end();
}).listen(3001);

// try it
http.get('http://localhost:3000', function (res) {
  console.log("First try:", res.statusCode);

  http.get('http://localhost:3000', function (res) {
    console.log("Second try:", res.statusCode);
  });
});
kacperzuk commented 8 years ago

That works great, thank you.