Precise definition of Meteor call stubs and upgrade strategy to 2.11

We are in the process of upgrading to meteor 2.8 and then on towards 2.11, and are struggling a bit regarding some of the gotchas in the migration docs:

It details some of the gotchas regarding the new async features. The docs make frequent mention of how the async calls have limitations in some cases where stubs exist.

I understand the concept for stubs to accommodate for latency, but I am still confused about a few statements in the docs about exactly when stubs are created.

It says:

Calling methods on the client defines stub functions associated with server methods of the same name. You don’t have to define a stub for your method if you don’t want to. In that case, method calls are just like remote procedure calls in other systems, and you’ll have to wait for the results from the server.

If you do define a stub, when a client invokes a server method it will also run its stub in parallel. On the client, the return value of a stub is ignored. Stubs are run for their side-effects: they are intended to simulate the result of what the server’s method will do, but without waiting for the round trip delay. If a stub throws an exception it will be logged to the console.

When they say “Calling methods on the client defines stub functions” Do they mean Defining a Meteor.method in a file that is bundled on the client? So if a file is in a client directory and I define a meteor method in it, does that create the stub? What about if the file is in a directory like /lib?

If we already have Meteor Methods defined that are designated as async, let’s say they are only on the server right now, at what point in the migration do we need to modify this code and in under what scenarios? Do we need to ensure that all calls to that function now use callAsync? If those methods are still called with Meteor.call() what symptoms would we likely see?

1 Like

Hi,

The thing you need to worry about now is async methods that are defined in the client and using the new async MongoDB call.

Let’s say you have something like this in the client:

Meteor.methods({
    async save(data) {
          const id = await Coll.insertAsync(data);
          return id;
    }
})

If you call this method twice in a row (without waiting for the first to finish), that’ll be a problem because you’ll have two stubs processed simultaneously. Each call to a method creates a stub. That’s because in the client, after calling a method, Meteor makes a simulation to “forecast” the server result. This is also known as Optimistic UI.

If we already have Meteor Methods defined that are designated as async […]

If the method is only defined for the server, you won’t have this problem, because Meteor won’t create stubs for those calls.

Do we need to ensure that all calls to that function now use callAsync?

No. Just for the ones that are async. As a matter of fact, you can have the same method defined for both, server and client, but with different implementations:

// client
Meteor.methods({
    save(data) {
          const id = Coll.insert(data);
          return id;
    }
})

// server
Meteor.methods({
    async save(data) {
          const id = await Coll.insertAsync(data);
          return id;
    }
})

Now you don’t need to worry about racing in the client, because you call simply call this method using Meteor.call().

If those methods are still called with Meteor.call() what symptoms would we likely see?

This section of the 2.8 guide should answer this.

My advice would be to start with the server. Start using the new async MongoDB API on the server side. Once you have everything working on that side, focus on the client using these examples as a guide.

1 Like

Thank you, that is very helpful. Maybe you addressed this already, but for clarity, what happens if you have a method defined in, say, /lib, so it is defined on both the client and the server?

Hi, the section that was shared with you contains the answer. You can check the // SERVER side and then the // CLIENT code. When you have method outside a “client” or a “server” folder, such as the “/lib” code, you look at it in that exact framework from the Meteor document (the stubs further down in the document).

I’d like to jump on to this thread and ask 3 clarifying questions. On its face, the migration looks mechanical, tedious, and straight-forward.

  1. We added a pattern long time ago (pre 2.8) where we defined some our Meteor methods as ASYNC so we could use AWAIT inside their implementation. Will this cause any problem in 2.11 update? These are “mixed-mode” b/c they use await for some code and they use fibers (mongo wrappers) for everything else.

  2. What will happen to an “old” Cordova app that has not been updated? When it calls “doSomething” which has been re-implemented using async, will the server implementation be hidden from the caller and will the old client continue to work?

  3. We have ZERO client-side methods that we define. But, collection.update() is an example where there is both a client and server method. We don’t use many of these, and we swap out the server implementation at run-time with our own custom code. What’s going to happen with these stubs? Are there going to be 2 versions? Or just 1 version that is ASYNC? and will old clients (Cordova) continue to work using the pre “async” version of update?

Thanks!