Fix #8457 by filtering exceptions when 'noRetry' flag is set. (#8496)

This commit is contained in:
Ahmed Akram
2017-03-17 05:21:01 +02:00
committed by Ben Newman
parent fe380e3efc
commit b59513540e
2 changed files with 35 additions and 28 deletions

View File

@@ -299,29 +299,22 @@ var Connection = function (url, options) {
if (self._outstandingMethodBlocks.length > 0) {
// If there is an outstanding method block, we only care about the first one as that is the
// one that could have already sent messages with no response, that are not allowed to retry.
_.each(self._outstandingMethodBlocks[0].methods, function(methodInvoker) {
// If the message wasn't sent or it's allowed to retry, do nothing.
const currentMethodBlock = self._outstandingMethodBlocks[0].methods;
self._outstandingMethodBlocks[0].methods = currentMethodBlock.filter((methodInvoker) => {
// Methods with 'noRetry' option set are not allowed to re-send after
// recovering dropped connection.
if (methodInvoker.sentMessage && methodInvoker.noRetry) {
// The next loop serves to get the index in the current method block of this method.
var currentMethodBlock = self._outstandingMethodBlocks[0].methods;
var loopMethod;
for (var i = 0; i < currentMethodBlock.length; i++) {
loopMethod = currentMethodBlock[i];
if (loopMethod.methodId === methodInvoker.methodId) {
break;
}
}
// Remove from current method block. This may leave the block empty, but we
// don't move on to the next block until the callback has been delivered, in
// _outstandingMethodFinished.
currentMethodBlock.splice(i, 1);
// Make sure that the method is told that it failed.
methodInvoker.receiveResult(new Meteor.Error('invocation-failed',
'Method invocation might have failed due to dropped connection. ' +
'Failing because `noRetry` option was passed to Meteor.apply.'));
}
// Only keep a method if it wasn't sent or it's allowed to retry.
// This may leave the block empty, but we don't move on to the next
// block until the callback has been delivered, in _outstandingMethodFinished.
return !(methodInvoker.sentMessage && methodInvoker.noRetry);
});
}

View File

@@ -819,34 +819,48 @@ if (Meteor.isClient) {
startAndConnect(test, stream);
var methodCallbackFired = false;
var methodCallbackErrored = false;
var firstMethodCallbackFired = false;
var firstMethodCallbackErrored = false;
var secondMethodCallbackFired = false;
var secondMethodCallbackErrored = false;
// call with noRetry true so that the method should fail to retry on reconnect.
conn.apply('do_something', [], {noRetry: true}, function(error) {
methodCallbackFired = true;
firstMethodCallbackFired = true;
// failure on reconnect should trigger an error.
if (error && error.error === 'invocation-failed') {
methodCallbackErrored = true;
firstMethodCallbackErrored = true;
}
});
conn.apply('do_something_else', [], {noRetry: true}, function(error) {
secondMethodCallbackFired = true;
// failure on reconnect should trigger an error.
if (error && error.error === 'invocation-failed') {
secondMethodCallbackErrored = true;
}
});
//The method has not succeeded yet
test.isFalse(methodCallbackFired);
// reconnect.
// The method has not succeeded yet
test.isFalse(firstMethodCallbackFired);
test.isFalse(secondMethodCallbackFired);
// send the methods
stream.sent.shift();
// "receive the message"
stream.sent.shift();
// reconnect
stream.reset();
// verify that a reconnect message was sent.
testGotMessage(test, stream, makeConnectMessage(SESSION_ID));
// Make sure that the stream triggers connection.
stream.receive({msg: 'connected', session: SESSION_ID + 1});
//The method callback should fire even though the stream has not sent a response.
//the callback should have been fired with an error.
test.isTrue(methodCallbackFired);
test.isTrue(methodCallbackErrored);
test.isTrue(firstMethodCallbackFired);
test.isTrue(firstMethodCallbackErrored);
test.isTrue(secondMethodCallbackFired);
test.isTrue(secondMethodCallbackErrored);
// verify that the method message was not sent.
test.isUndefined(stream.sent.shift());