-
Notifications
You must be signed in to change notification settings - Fork 215
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
feat(notifier): subscribeEach/subscribeLatest iterators retry when broken by vat upgrade #7401
Conversation
That makes sense. But I'm somewhat worried about what that means for these consumers, especially since it seems they may be using
Could we annotate the rejection with the upgraded rejection? |
548ed4c
to
36ee17b
Compare
aad76d2
to
0e926a7
Compare
Updated to opportunistically reconnect subscribeEach iterators when possible per #5185 (comment) . |
This PR introduces a locally-reproducible failure for the "Watch interest accrue" test in test-stakeFactory.js that might be real— name: AssertionError
assertion: deepEqual
values:
'Difference (- actual, + expected):': |2-
{
brand: Object @Alleged: IST brand {},
- value: 194796320n,
+ value: 195000000n,
}
at: >-
approxEqual
(packages/inter-protocol/test/stakeFactory/test-stakeFactory.js:507:7)
Object.checkRUNDebt
(packages/inter-protocol/test/stakeFactory/test-stakeFactory.js:742:7)
async packages/inter-protocol/test/stakeFactory/test-stakeFactory.js:991:3 I'm not sure how |
@gibson042 thanks for the detailed question. @dckc and I conferred and agree with your conclusion. For appropriate |
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.
Looking good! Just a few comments that shouldn't block approval.
}); | ||
harden(makeUpgradeDisconnection); | ||
|
||
// TODO: Simplify once we have @endo/patterns (or just export the shape). |
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 do have @endo/patterns
now.
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.
My first attempt didn't quite work, so I'm deferring this until we've got a little more time to spend on it.
packages/notifier/src/subscribe.js
Outdated
// rejections here too to avoid invalid unhandled rejection issues later. | ||
void E.when(publishCountP, sink, sink); | ||
void E.when(nextCellP, sink, sink); |
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.
I'm uncertain about why publishCountP
is sunk, but tailP
(originally pubList
at this point) is not. Can you elaborate (either by replying here, or in a code comment) as to why these two calls are necessary?
I suspect that there may be a clearer way to avoid introducing any unhandled rejections with minimal sinks. I just don't see it right now.
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.
Any rejection of tailP
would be handled in reconnectAsNeeded
.
const firstCellP = reconnectAsNeeded(() => E(topic).subscribeAfter()); | ||
return makeEachIterator(topic, firstCellP); |
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.
This is really clear!
…grade subscribeEach iterators continue to fail in that scenario, because they cannot guarantee absence of gaps. Fixes #5185
…onnection Depends upon PublishKit `publishCount` being a gap-free sequence of bigints.
2ec199f
to
e6d65d0
Compare
Fixes #5185
Description
"latest" iterators look for rejections that indicate failure due to vat upgrade, and upon encountering them retry the
getUpdateSince
call—if the source is durable, the retry will succeed and provide the next iteration result. If the source is not durable, the retry will go splat and the error associated with that will be propagated in place of the vatUpgraded rejection (which is perhaps unfortunate, but seems to be the only way of guaranteeing that a realfail
result with unfortunate timing is not replaced by a vatUpgraded rejection)."each" iterators behave similarly, but additionally fail if multiple values are published before they can successfully reconnect because they cannot tolerate gaps in the sequence.
Security Considerations
A malicious source can fake vatUpgraded rejections, which the "latest" iterators will dutifully accept and respond to by retrying as long as
incarnationNumber
indicates forward progress. Something like this is necessary to handle the edge case where a second upgrade occurs in between the consumer receiving a rejection and the producer receiving the retry, but we could put in a retry count limit if this is perceived as an actual risk.Scaling Considerations
I don't think this affects scaling.
Documentation Considerations
These relatively fine implementation details are covered by JSDoc comments.
Testing Considerations
The rapid-upgrade edge case is not covered by testing, but I consider that acceptable. If reviewers disagree, I think I can add a new file with manually-constructed mock producers.