Dave Sag
Dave Sag

Reputation: 13486

Using Async and Promises that are all rejected leads to async never completing

I'm using async and promise to run a seeding script but in the case where all promses are rejected the script never completes.

As it's a seeding script it's set up to not seed models that alredy have data.

Here's (abridged) my code

Any idea what I've missed?

seed = function(collectionName, data) {
  return new Promise(function(fulfill, reject) {
    var collection = collections[collectionName];
    collection.find().exec(function(err, found) {
      if (found.length > 0) {
        console.log("There are", found.length, collectionName, "records in the database already.");
        reject();
      } else {
        collection.createEach(data, function(err, models) {
          if (err || _.isUndefined(models)) {
            console.log("Could not create", collectionName, "collection!");
            reject();
          } else {
            collection.find().exec(function(err, found) {
              fulfill(found);
            });
          }
        });
      }
    });
  });
};

run = function(models, done) {
  async.each(models, function(modelName, next) {
    seed(modelName, modelData[modelName]).then(function(codes) {
      console.log("Seeded", codes.length, modelName, "records.");
      next();
    }, function(err){
      console.log("Seeding of", modelName, "failed", err.stack);
      done(err);
    });
  }, done);
};

run(["widget", "thingo", "dooverlackey"], function(err){
  if (err) console.error("Completed with errors", err);
  else console.log("Completed without errors");
  process.exit();
});

Upvotes: 0

Views: 55

Answers (1)

jfriend00
jfriend00

Reputation: 708116

In your code, if you reject on a call to seed(), then your code will go to the reject handler in your .then() where you call done(). So, your own structure has told it to stop processing if it gets a rejection in this code:

seed(modelName, modelData[modelName]).then(function(codes) {
  console.log("Seeded", codes.length, modelName, "records.");
  next();
}, function(err){
  console.log("Seeding of", modelName, "failed", err.stack);
  // upon fail from seed, stop processing
  done(err);
});

You can either change your reject handler (the second callback passed to .then()) so that it continues processing or you can change seed() to only reject if there is a serious error that you cannot continue from.

Though there are many different ways to use promises, it's probably more conventional to reserve the reject for a serious failure that you cannot continue from which would mean changing your seed() function to only reject() if there's a serious error. When it merely finds that it doesn't have anything to do because the work has already been done, it would just resolve() and let the whole process continue.

Upvotes: 2

Related Questions