express-http-proxy
express-http-proxy copied to clipboard
Offline timeout (retrier)
I have a case: all request are happening like that: browser → proxy → nodejs local server (on 3000 port). My local server could be offline (relaunching after source update), and I need browser-to-proxy connection to be alive (wait for relaunch). Instead I get instant
Error: connect ECONNREFUSED 127.0.0.1:3000
at Object._errnoException (util.js:1026:11)
at _exceptionWithHostPort (util.js:1049:20)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1174:14)
timeout parameter not working here.
Is there any way to solve my case?
Interesting. There is no current code in place to handle this case on your behalf.
For the short term, I'd consider something like:
app.use( proxyMatchingPath, waitForServerOnline);
app.use( proxyMatchingPath, proxy(....) );
Where waitForServerOnline performs a health check for your local server -- which could be offline -- before proceeding on to the proxy functionality.
I'd consider a patch that makes this an opt-in feature for express-http-proxy; this is not a feature I'd prioritize for writing myself in the near term.
Best of luck and thanks!
A thing to keep in mind -- node.js doesn't cache dns, which means there is no guarantee dns will resolve to the same endpoint from one http request to the next.
For example, consider if your target has RRDNS and only one of the hosts are down.
waitForServerOnline may resolve dns to an active node, but the second proxy could resolve to an inactive. Or of course the opposite.
This is just a problem with node.js that won't be fixed (i've tried). That leaves doing inline retries as OP suggests.
I had this exact same problem that I was trying to solve, and @monkpow's suggestion worked like a charm! Thanks!
And if someone is interested in how I did it, here a snippet:
const proxy = require('express-http-proxy');
const fetch = require('node-fetch');
const Rx = require('rxjs/Rx');
const express = require('express');
const app = express();
app.use('/', (req, res, next) => {
Rx.Observable.of('http://localhost:3000/build')
.switchMap(url => Rx.Observable.fromPromise(fetch(url)))
.retryWhen(errors =>
errors
.delay(100) // Delay for 100ms before retrying
.take(10) //Retry 10 times
.concat(Rx.Observable.throw('FAILED AFTER 10 retries'))
)
.subscribe(
() => {
next();
},
() => {
res.status(500).send('Failed to connect to proxied server');
}
);
});
app.use('/', proxy('localhost:3000'));
I just found this issue for a slightly different reason, wondering if @monkpow could comment. We're using express-http-proxy to proxy requests to a server that requires authentication. The access token used for the Authorization header may not yet have expired, but for whatever reason, it's been invalidated within the proxied server (say, for example, because of a "log out all sessions" or similar piece of functionality). In that case, I'd like to intercept the 401 or 403 response, get a new token, then retry the request and, if the retry fails for any reason (auth or otherwise), return the failed response.
I understand the waitForServerOnline strategy above. What might a strategy be for my retry-on-auth-failure use case?