Migration to 2.8 Async version

Thank you @radekmie

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:

1 Like

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.

Thank you for your work.

3 Likes

Hi @pbeato,

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…

I think @radekmie can answer this one.

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.

1 Like

To make sure I understand, the sync version of minimongo will kept or removed from the client in Meteor 3?

1 Like

I would recommend something more collaborative than a discussion to avoid the core team being bottlenecks.
Maybe a shared google doc where people can contribute? Or does this board thing or github have something like a wiki page?

Everything should be async.

I’m afraid a google doc can be too messy… At least on Github, it looks easier to chime in, like in this discussion.

BUT we can find a better place if the community doesn’t like it there, not a problem.

EDIT: I think that instead of a discussion I can create a new MD file in the Meteor repository, like this one, so everyone can collaborate. Then people can easily access it here in our guide. What do you think?

1 Like

Idk - at this time I feel we need something highly collaborative without any approval workflow, like a wiki page

Thanks @denyhs,

I think that forcing the switch to asynchronous logic on the client side as well will bring an ultimately unnecessary amount of conversion work. I fully understand the motivations, but let’s keep the legacy code in mind. In the Blaze environment, all the reactivity contexts should be reviewed: helpers, autoruns, dependencies and the associated call chains; basically, the entire code and the associated tests should be completely revised. To date, there is not even the possibility of doing this as Blaze does not yet support this model. Then, it would only be a matter of bringing mimic asynchronous with a Promise.resolve, I don’t think you want to bring minimongo to a native asynchronous version. I can assure you that, for applications like ours with thousands of lines of code, it is impressive work, bordering on a complete rewrite of the code.

Already the rewriting of the asynchronous server context is forcing us to distinguish the code between server and client in order to make up for the Tracker’s shortcomings, we would then have to revise everything to bring it back to its initial state, doesn’t that seem a bit too complex a migration process?

When I was talking about a possible underestimation of the client side (see here), I was referring to these outstanding points, it seems to me that we are still working on sight.

2 Likes

I completely agree with @pbeato.

The client-side source conversion would not be an adaptation but a complete rewrite of the source with all the consequences of the case and moreover without a real reason.

In fact, for a new application designed from scratch it would certainly be cleaner to have the async code also on the client side but, since unlike the server (Fiber and Node…) there is no intrinsic reason to have everything async, I think that as far as the client is concerned, guaranteeing both ways (sync and async) could be the wisest choice to avoid that many applications, having to be completely rewritten, end up abandoning Meteor completely.

I urge you to consider this possibility.

2 Likes

Considering that we already don’t have Fibers on the client, it might be possible to keep Mongo sync in the client.

I’ll need to confirm if this would be possible.

Maybe @radekmie could already confirm?

EDIT: So yeah, apparently we should be able to keep both actually. The sync version should continue to work. But in the future, we’ll need to worry about renaming the API or not (client side). We could keep the method updateAsync, or rename the current sync one to updateSync. But this is something we can all decide when the moment arrives.

3 Likes

I think @rtrevisan’s reasons are absolutely valid.
As far as our application (meteor+blaze) is concerned, a lot of effort will be required for server-side porting. Since the client could be kept synchronous, I would expect not to be forced to modify it, at least in a first step

Yeap, that’s the idea. We want to do this avoiding forcing things that don’t need to be forced.

2 Likes

I think it should be decided now, let me try an example:

Suppose we have a simple function now shared between client and server and used, client-side in a Blaze helpers or autorun and server-side in a method:

function hasPrivilege(prv) {
return userPrivileges.findOne( { _id: Meteor.user()._id, privilege: prv })
}

On the server side I would have to rewrite it asynchronously and change the whole call chain to support the new signature:

async function getPrivilege(prv) {
return await userPrivilegesAsync.findOne( { _id: (await Meteor.userAsync())._id, privilege: prv })
}

While on the client side I would have to keep the function synchronous, losing the isomorphic nature of Meteor that allowed client/server code sharing.

When reverting to the standard nomenclature, things are reversed:

Server-side

async function hasPrivilege(prv) {
return await userPrivileges.findOne( { _id: (await Meteor.user())._id, privilege: prv })
}

While on the client side we have

function hasPrivilege(prv) {
return userPrivileges.findOneSync( { _id: Meteor.userSync()._id, privilege: prv })
}

A migration that becomes really complicated and with a high probability of writing unnecessary chunks of code.

There must be other ways of doing this that I can’t see at the moment.

I would also like to know the opinion of those who are in charge of the product in order to reassure us users about the overview.

I still think that a flag and a Promise for observe and observeChanges would be enough, but I didn’t got time to experiment with it yet.

I wrote it a couple of times, but I can’t find it now. It’s true, that we can keep the sync APIs on the client, but the question is how does it affect the isomorphic code (i.e., server-side). One solution is to have them on the server but throw an error immediately, second is to make them no-op (e.g., fetchSync would return an empty array, updateSync wouldn’t do anything), third is not add them at all. All have some solid pros and cons.

At the same time, nothing stops you from renaming the functions in the app, so…

As I understand, the only way to make codes work on both client and server without separating client/server codes is using async api on both sides.
e.g:

const links = await Links.find({}).fetchAsync();

If we have sync api on client and async on server, it would be like this:

let links;
if (Meteos.isClient) {
  links = Links.find({}).fetch();
} else {
  links = await Links.find({}).fetchAsync();
}

So the function which has those code must be async as well. Then it doesn’t make sense to use the sync version in share code.

So have a version of sync api on the client-side: updateSync, fetchSync could be better.
On the server-side, it should throw error because “does nothing” is dangerous, it’s hard to find where the problem is.