-
Notifications
You must be signed in to change notification settings - Fork 214
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
async buildRootObject #5246
Comments
Is it considered a valid practice to inspect the return value from a function to see if it's a Promise or not? Or even not look but just fail if a Promise comes back. Because I'd like us to be able to continue using fully synchronous |
It's frowned up. The main problem is dealing with |
Our tests are not going to be returning evil thenables. |
I think we can have |
New (or upgraded) vats are defined by a user-provided `buildRootObject` function. This function has two responsibilities: * provide a root object * use `defineDurableKind` to bind behavior to any pre-existing durable kinds Previously, `buildRootObject` was given exactly one "turn" to fulfill these responsibilities: it was required to return the root object synchronously. If it returned a Promise, that was rejected as an error. This requirement is at odds with the needs for updated ZCF vats to evaluate their contract code and interact with it (giving the contract a chance to bind their own Kind behavior). The `importBundle` function we use to load contracts is async. However, it is still "prompt": it needs no IO, nor any messages leaving the vat. So it will still complete within the *crank*, just not synchronously within the turn. So this commit changes liveslots to allow `buildRootObject` to return a Promise for the root object. The requirement, however, is that this Promise must resolve by the end of the initial crank (before `waitUntilQuiescent` / `setImmediate` determines that the promise queue is empty). If the Promise is not fulfilled by then, the vat creation/update is considered broken. closes #5246
New (or upgraded) vats are defined by a user-provided `buildRootObject` function. This function has two responsibilities: * provide a root object * use `defineDurableKind` to bind behavior to any pre-existing durable kinds Previously, `buildRootObject` was given exactly one "turn" to fulfill these responsibilities: it was required to return the root object synchronously. If it returned a Promise, that was rejected as an error. This requirement is at odds with the needs for updated ZCF vats to evaluate their contract code and interact with it (giving the contract a chance to bind their own Kind behavior). The `importBundle` function we use to load contracts is async. However, it is still "prompt": it needs no IO, nor any messages leaving the vat. So it will still complete within the *crank*, just not synchronously within the turn. So this commit changes liveslots to allow `buildRootObject` to return a Promise for the root object. The requirement, however, is that this Promise must resolve by the end of the initial crank (before `waitUntilQuiescent` / `setImmediate` determines that the promise queue is empty). If the Promise is not fulfilled by then, the vat creation/update is considered broken. closes #5246
What is the Problem Being Solved?
#3272 turns out to have a surprising requirement: we need to do
importBundle
(which is async, for deep reasons) from insidebuildRootObject
(which is sync). This comes from ZCF needing to import the new version of the contract, then invoke the contract method that re-establishes behavior for the durable Kinds, all of which needs to happen before the end of thebuildRootObject
delivery (so it can execute the normal deliveries that will immediately follow).D(bundlecap).getBundle() -> bundle
is synchronous, for exactly this reason, but I forgot thatimportBundle
is async.Description of the Design
It looks like making liveslots tolerate an async
buildRootObject
is the best way to deal with this. The tricky part is the error handling, in particular what to do if the user-providedbuildRootObject
function returns a Promise that never resolves. We must prevent userspace from hanging the supervisor.The tail end of
startVat
currently does:and the code which calls it is basically:
I'm thinking the trick will be to connect the
buildRootObject
promise to a function that finishes thestartVat
process, then sets a flag. We return a separate promise fromstartVat
. I need a way for that second promise to reject if the flag isn't set at the timewaitUntilQuiescent
fires. That probably means introducing a callback into the() => p
portion, to query the flag.Security Considerations
Main requirement is to not allow an unresolved userspace promise to hang the worker (and kernel).
Test Plan
unit tests
The text was updated successfully, but these errors were encountered: