I have started the migration of a large application. I have a few doubts concerning some primitives that maybe some of you have already dealt with:
forEachAsync,mapAsync: the callback remained synchronous, in case an asynchronous function needs to be called within it (e.g. an additional call to mongo) , it should become asynchronous.
observe: in the synchronous version, the method added for records already in the db was called before terminating the invocation, in the asynchronous version should it be considered asynchronous?
Blaze: will using a find in response from a helper still work? Should all functions that have become asynchronous in minimongo (e.g. findOneAsync) be converted to reactiveVar when used in a helper?
For that blaze question we do have an issue here on blaze repo and I think @storyteller & @jkuester may have a better understanding on this
forEachAsync,mapAsync question: I think it would be okay, because as you are waiting on the promise to be solved it should make sense.
You can make you forEachAsync and mapAsync into for: as @radekmie said in his pr
await (const document of collection.find(query, options)) /* ... */
for the observe question I could not understand properly. Can you provide some pseudo/real code so that I can think on top of it?
like you are saying something like this?
there is this first pr as well with more examples of asyncMongo code
Iāve been wondering the same thing regarding observe and observeChanges. In the docs, it says
Before observe returns, added (or addedAt ) will be called zero or more times to deliver the initial results of the query.
This is frequently used to differentiate between docs that already exist, and new docs. How does this work with the async api?
An example of how it currently is used:
let initialAdd = true;
const handle = cursor.observe({
added(id) {
if (initialAdd) {
// Doc that already existed in mongo or minimongo
} else {
// Is new doc
}
}
});
initialAdd = false;
the solution proposed by @radekmie surely works, it was to avoid rewriting dozens of forEach/mapEach. Otherwise I will write a jscodeshift codemod to do it :-(.
Regarding observe I quote the @zodern in the previous post.
It would not hurt, at this time of migration, to create a set of shared recipes for common problems.
The goal, for now, was to make the async API available, though the code is still synchronous. Making forEachAsync and mapAsync work with async functions is a sane requirement. However, MongoDB driver itself, requires forEach callback to be synchronous and uses the returned value a way to stop the iteration (source). Therefore, at least for now, I wouldnāt change it at all.
As for the observe and observeChanges methods, I donāt have the answer yet. From the top of my head, making them return not only stop but also something like isInitial flag or even initialAddsSent promise seems feasible, although Iām not sure if an entirely good approach.
The Meteor.user() call most likely becomes asynchronous, right?
The invocation of server-side methods (Meteor.callā¦), now synchronous due to fiber, I assume will become asynchronous, right? Now, we use a promise version of call, but only client-side.
Do any of you have an idea of the approach that will be used in the kernel in replacing fibre. If we use async/await logic most of the functions will become asynchronous, the impact is almost like writing a new application.
Yes exactly. You will need to assume that every single serverside method X in meteor core and every package will be replaced by an XAsync method that you must switch to and adapt your own code accordingly. That is the price we must pay for replacing fibers with async/await.
As for client side code and if it will be possible to keep code isomorphic the jury is still out.
There are some cases already where it seems hard and client side code will need to keep invoking the existing sync versions like collection.findOne
Just think of the Tracker, cornerstone of all Meteor reactivity, but still synchronous and based on global variables. The question I have is: Is it worthwhile to start porting to the asynchronous client-side version of Mongo with still all these blind spots?
@radekmie Throw new Meteor.Error(āānot-authorizedāā) is no longer thrown in an async method.
example:
new ValidatedMethod({
name: 'getOrgPeopleAndRoles',
validate: new SimpleSchema({
_id: String
}).validator(),
async run ({ _id }) {
if (!this.userId) { throw new Meteor.Error('not-authorized') }
// ....
The error will not throw but the method will be interrupted. Throwing the error in an async context requires a catch apparently.
Example:
new ValidatedMethod({
name: 'getOrgPeopleAndRoles',
validate: new SimpleSchema({
_id: String
}).validator(),
async run ({ _id }) {
const checkUser = async () => {
if (!this.userId) { throw new Meteor.Error('not-authorized') }
}
checkUser()
.then(() => // method content here )
.catch(e => console.log(e)) // but I can only console log it, it does not reflect on the client like it used to.
In the catch is where I can log the error on the server console but as mentioned it does not show on the client side.
Are there any suggestions for how to throw an error like if (!this.userId) { throw new Meteor.Error('not-authorized') } in 2.8?
This should be part of the recommended code updates in the migration guide I think.
I might have tagged you by mistake on this one, I thought you were part of the Meteor team.
Anyway, the issue I was referring to in my previous message is related to Error handling in async in NODE, in general. The fact that we move to async, changes the way NODE Error works.
I know that async context handles erorrs differently, but I still donāt understand whatās the problem ā if you await it, your error will be ācatchableā.
As discussed in previous threads, maintaining minimongoās client-side synchronous functions in the future could be a first step towards supporting node 16. I understand that we would have to revise Meteorās isomorphic logic, but at least we would have the client working as before and we could concentrate on server-side changes. Already the transition to the server-side asynchronous version will be heavy and complex, adding the client side as well could be untenable. Guaranteeing everything by April may not be plausible.
On the application side, we have to make a lot of changes to adapt to the new architecture, this also has a timeframe that will naturally go beyond April 2023, we will have installations in production without Node support, which is worrying.
I would like to discuss these issues for proper planning of our releases.
Hello everybody, we also have an application that uses React + Redux on the client and Meteor on the server side.
In particular, we use Minimongo on the client side to obtain the collection modification events and consequently perform the status update in redux.
For this purpose we have some code written exactly like in the example of @zodern .
I agree with @pbeato on the fact that in a first phase it would be worth keeping the synchronous Minimongo solving the node compatibility problem only on the server side.
Thanks for your help.
I have tried using zone.js within Tracker without success because zone.js does not intercept native promises (async/await, see #11670). Now, does anyone know of an alternative library to do this?
I tried with the legacy bundle and zone.js works but it feels like going back in time.
Never mind, I found a satisfactory way to deal with it by calling throw new Error('not-authorized') instead of throw new Meteor.Error('not-authorized').
With Meteor.Error I can catch the error on the client, print it and it retains the err => err.error message as thrown on/by the server. However, with Meteor.Error the error is not thrown on the server console. I donāt get a
Exception while invoking method '.......' Error:not-authorized
With throw new Error(), I get the behavior from the āoldā sync methods, it throws an exception on the server and I can catch it on the client, however on the client it does not retain the error message and it only shows a generic error: 500 which I am fine with.
I will have to dig some more to see what is changing in the Meteor.Error in the async environment cause it definitely behaves differently.
I have started a MCP discussion related to this, I want to coordinate updating the MCP packages and establish new common patterns on how to deal with any issues that come our way. Now with 2.8 released and more on its way as you upgrade I would very much appreciate everyoneās feedback on this in the discussion:
I return to this topic because the steps required for migration are still unclear. With my team we are in the process of revising the code of a large application, and we need to know what the future holds.
I still report on the nebulous points.
When the migration of mongo calls is complete, will asynchronous methods be renamed without the *Async suffix? topic
Will the synchronous version of the client-side mongo methods be retained? If so, will the *Sync suffix be added?
Will the added method of the observers be asynchronous or will an attribute be added to the call to indicate that it is loading the query result? What should we expect on the client side? comment
Will the bindEnvironment and wrapAsync methods be removed or rewritten to support session context logic without Fiber (async_hook)?
Little is said about the client context, in our case Blaze. Is there a strategy describing the end goal? Otherwise, we will be forced to revise the code many times.
In my opinion, it would be a good idea to aggregate all the information relating to this migration in one place. Now one is forced to navigate through dozens of PR/issue/forums/slack to get an unvalidated infomation. There is the migration document but it is released after the actual implementation without any indication of the client/server end point.
will asynchronous methods be renamed without the *Async suffix?
Yes, eventually. In version 3.0 update() and updateAsync will work exactly the same (this goes the same for the other methods). But weāre not going to remove them immediately. It wouldnāt make sense. Eventually, down the road, weāre going to depreciate them, and then later, remove them. So donāt be afraid to commit to them now.
Will the synchronous version of the client-side mongo methods be retained? If so, will the *Sync suffix be added?
No. It will be as it is today.
Will the bindEnvironment and wrapAsync methods be removed or rewritten to support session context logic without Fiber (async_hook)?
We are reviewing these two functions actually. We believe that in version 3 we wonāt need them anymore. Weāll probably remove them.
Will the added method of the observers be asynchronousā¦
Little is said about the client context, in our case Blazeā¦
Iām not sure I understood this one, sorry. What do you mean by client context?
it would be a good idea to aggregate
Yes! Iāll start working on creating a new discussion that will work as a migration guide. The idea will be to have a place where you can go and from there get the answers you need.
Iāll post the first version of this discussion soon, and from there we can improve it with time.