-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Create noRetry option on Connection.apply #6180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
451db19
246fb00
0ddbc65
6707d33
3744870
93fb4b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -274,11 +274,44 @@ var Connection = function (url, options) { | |
msg.support = self._supportedDDPVersions; | ||
self._send(msg); | ||
|
||
//Mark non-retry calls as failed This has to be done early as getting these methods out of the current block is | ||
// pretty important to making sure that quiescence is properly calculated, as well as possibly moving on | ||
// to another useful block. | ||
|
||
// Only bother testing if there is an outstandingMethodBlock (there might not be, especially if we are connecting | ||
// for the first time. | ||
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. | ||
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(Meteor.Error(409, 'Method is non-idempotent but attempted to call a second time', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would change this to an error string - for example There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I was actually going to change that just as soon as I got home after re-reading the style guide today. If 'invocation-failed' is used, the test should also be updated to expect that. |
||
'Method result is unknown due to dropped connection. This method request was marked to not retry'), undefined); | ||
} | ||
}); | ||
} | ||
|
||
// Now, to minimize setup latency, go ahead and blast out all of | ||
// our pending methods ands subscriptions before we've even taken | ||
// the necessary RTT to know if we successfully reconnected. (1) | ||
// They're supposed to be idempotent; (2) even if we did | ||
// reconnect, we're not sure what messages might have gotten lost | ||
// They're supposed to be idempotent, and where they are not, | ||
// they can block retry in apply; (2) even if we did reconnect, | ||
// we're not sure what messages might have gotten lost | ||
// (in either direction) since we were disconnected (TCP being | ||
// sloppy about that.) | ||
|
||
|
@@ -352,6 +385,7 @@ var MethodInvoker = function (options) { | |
self._message = options.message; | ||
self._onResultReceived = options.onResultReceived || function () {}; | ||
self._wait = options.wait; | ||
self.noRetry = options.noRetry; | ||
self._methodResult = null; | ||
self._dataVisible = false; | ||
|
||
|
@@ -369,10 +403,10 @@ _.extend(MethodInvoker.prototype, { | |
if (self.gotResult()) | ||
throw new Error("sendingMethod is called on method with result"); | ||
|
||
|
||
// If we're re-sending it, it doesn't matter if data was written the first | ||
// time. | ||
self._dataVisible = false; | ||
|
||
self.sentMessage = true; | ||
|
||
// If this is a wait method, make all data messages be buffered until it is | ||
|
@@ -703,6 +737,7 @@ _.extend(Connection.prototype, { | |
* @param {Object} [options] | ||
* @param {Boolean} options.wait (Client only) If true, don't send this method until all previous method calls have completed, and don't send any subsequent method calls until this one is completed. | ||
* @param {Function} options.onResultReceived (Client only) This callback is invoked with the error or result of the method (just like `asyncCallback`) as soon as the error or result is available. The local cache may not yet reflect the writes performed by the method. | ||
* @param (Boolean) options.noRetry (Client only) if true, don't send this method again on reload, simply call the callback with the error | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The documentation is generated from here, see how to update it in this hackpad: https://meteor.hackpad.com/Automatically-Generating-API-Docs-using-JSDoc-EpPmd2iuFEH There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And I see now that I somehow did parenthesis instead of braces, otherwise the documentation will update as needed. |
||
* @param {Function} [asyncCallback] Optional callback; same semantics as in [`Meteor.call`](#meteor_call). | ||
*/ | ||
apply: function (name, args, options, callback) { | ||
|
@@ -885,7 +920,8 @@ _.extend(Connection.prototype, { | |
connection: self, | ||
onResultReceived: options.onResultReceived, | ||
wait: !!options.wait, | ||
message: message | ||
message: message, | ||
noRetry: !!options.noRetry | ||
}); | ||
|
||
if (options.wait) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to list these options here, right? They should be in the API box above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, missed that the api box was there, glad it's not needed.