I've got a somewhat complicated flow that receives an entryUrl
from a database, checks where it redirects to, and then updates it with an exitUrl
.
Basically the flow should be like so:
- retrieve an
Url
without an exit url- get the
Url.entryUrl
's headers usingrequest
- if there's an unexpected response or connection was reset, flag this
Url
and continue with the next one
- if there's an unexpected response or connection was reset, flag this
- parse the
exitUrl
resulting from therequest
performed- store the
exitUrl
- continue with the next
Url
- store the
- get the
- if no
Url
available, try again after 5 seconds - if any unexpected error in the above chain or subchains, try again after 60 seconds
My current implementation is like so, using the Bluebird javascript promise style:
function processNext() {
return api.getUrlWithoutExitUrl()
.then(function followEntryUrl(url)
{
if (!url || !url.entryUrl)
{
throw new NoUrlAvailableError();
}
log.info('getting exit url for ' + url.entryUrl);
return [
request({
method : 'HEAD',
url : url.entryUrl,
followAllRedirects : true,
maxRedirects : 20
})
.catch(ResponseError, function()
{
log.error('got strange response');
})
.catch(ConnResetError, function()
{
log.error('connection was reset');
})
.then(function removeInvalidUrl()
{
log.info('remove invalid url'); //FIXME: after doing this, we should not continue with the other `then` calls
}),
url
];
})
.spread(function parseExitUrl(res, url)
{
if (!res[0] || !res[0].request || !res[0].request.uri || !res[0].request.uri.href)
{
throw new InvalidUrlError();
}
return [res[0].request.uri, url];
})
.spread(function storeExitUrl(parsedExitUrl, url)
{
return api.setUrlExitUrl(url, parsedExitUrl);
})
.then(processNext)
.catch(InvalidUrlError, function()
{
log.info('an attempted url is invalid, should set as processed and continue with next immediately');
})
.then(processNext)
.catch(NoUrlAvailableError, function()
{
log.info('no url available, try again after a while');
})
.delay(5000)
.then(processNext)
.catch(function(err)
{
log.error('unexpected error, try again after a long while');
log.error(err);
log.error(err.constructor);
})
.delay(60000)
.then(processNext);
}
processNext();
function ResponseError(e)
{
return e && e.code === 'HPE_INVALID_CONSTANT';
}
function ConnResetError(e)
{
return e && e.errno === 'ECONNRESET';
}
Now, the problem is that if there's a ConnResetError
or a ResponseError
, the catch blocks are executed as they should be, but the then
blocks following the spread
call are also executed -- yet I want execution to stop after having done something after catching these 2 specific error types.
How would I achieve such flow of execution?
Just like in synchronous code - if you have a
catch
in which you want to perform some processing and then propagate the error - you can rethrow it:Synchronous code:
With promises: