Unable to serialize execution using Meteor.wrapAsync()

I am getting errors as two operations are overlapping in my startup code. One is inserting mock entities into some collections, the other operation is migrating the schema. I have only been successful in hacking the scheduling using timeouts, but I would like to have more control, so I am trying to use Meteor.wrapAsync().

From my index.js I am calling two methods:


import doMigrate from './migrations.js';
import doMockInsertions from './mock-entities';

Meteor.wrapAsync(doMigrate)();
Meteor.wrapAsync(doMockInsertions)();

The code looks like this

export default (done) => {
  try{ 
    Meteor.startup(()=> Migrations.migrateTo('latest'));
    done(null);
  }
  catch(err) {
    done(err);
  }
};
export default (done) => {
  try{ 
    doMockInsertions(); 
    done(null);
  }
  catch(err) {
    done(err);
  }
};

What am I doing wrong here? I want one operation to finish after the other. According to the docs the callback param is optional on the server side.

I think you may have misunderstood what Meteor.wrapAsync does. It’s used to wrap a function which has a callback with a (error, result) signature. So, it can be used to wrap classic asynchronous methods like HTTP requests to a REST endpoint.

Having said that, on the server standard Meteor MongoDB methods operate “synchronously”, so a series of operations on a collection will be done serially.

someList.forEach(doc => {
 someCollection.insert(doc);
});
someCollection.remove(somethingElse);

will be executed exactly as you write it. So:

doMigrations();
doMockInsertions();

will be processed in order as long as in those functions use standard Meteor MongoDB operations.

If you are not seeing that behaviour, could you share your doMigrate and doMockInsertions code?

1 Like

Actually, I was aware of the intent of wrapAsync, but I was getting desperate in trying to get the async behaviour under the control so I started reaching for whatever I could get hold of :smile: Actually, the code was originally just as simple as you showed, but still I could not get the operations not to overlap for some reason. I finally found the issue with liberal amounts of logging that included timestamps.

It was that there was some code doing insertions using the callback-style interface for Collections.insert(). That made it non-blocking.

So this diff was what was needed to make it blocking:

-      Patients.insert(patient, (err, patientId) => {
-        doSomething(patientId);
-      });
+      const patientId = Patients.insert(patient);
+      doSomething(patientId);

As I got errors about findOne being undefined if I removed the call to Meteor.startup() wrapping one of the calls, I opted to simply move the Meteor.startup() call to wrap both calls:

Meteor.startup( () => {
  doMigrations();
  doMockInsertions();
});

This worked, and I now get the operations serialized in the right order.