Struggling to understand why meteor is using so much computing power for this method on galaxy hosting

Recently I’ve put my app into semi-production and started experiencing some issues. Essentially one of the more CPU intensive methods was crashing my galaxy container. I contacted support and as expected, its because the method was requiring more ECU units than that was available to my container.

I initially has my app on a compact container, that means 0.5ecu. Here is the method that was causing the problem.

Keep in mind the base container when completely unused any client uses < 0.1 ECU.

export const menuOptionSetCreate = new ValidatedMethod({
  name: 'menu.optionset.create',
  validate: null,
  run({ option_set, dishesIn }) {
    let r = returnRestaurant();
    option_set._id = new Mongo.ObjectID()._str;
    if (dishesIn.length > 0) {
          for (let i = 0; i < r.dishes.length; i++) {
            for (let k = 0; k < dishesIn.length; k++) {
              if (r.dishes[i]._id == dishesIn[k]) {
                r.dishes[i].option_sets.push(option_set);
                break;
              }
            }
        }
     }
    Restaurant.update({ _id: r._id}, { $set: { dishes: r.dishes }});
    Restaurant.update({ _id: r._id }, { $push: { option_sets: option_set } });
    return true;
  }
});

I understand that there is a much more efficient way to write. I.e. just looping through this dishesIn, finding the index of the matching item in the dish list and pushing it.

I just want to know why is it struggling tho

At max a restaurant may have 100 dishes, so its not like there are that many records.

So i resized my container to the maximum size which provides 4.1ECU. I did this to see how much computing power this method required. When I ran the method, the container spiked to using 3.5+ ECU but stayed under the 4 mark.

Is this function really so CPU intensive that I need the max container size to run it? Also when I tried to move the code of the method to the client before the method is called, the server still struggles. Am I doing something wrong?

  1. Your outer loop is always running to completion. The break you have implemented only breaks the inner loop.
  1. You are updating the collection (in two places) even if there’s nothing to do.

  2. You are running the method on the client and the server (that’s what ValidatedMethod does by default). While that’s not always a bad thing, it’s probably unnecessary here.

Yes - I think you are using the proverbial sledgehammer here. I always get nervous when I see nested loops. I suspect there’s a super-efficient way of doing what you want to do, but without the background knowledge you have, no annotation in the snippet and (to me) meaningless variable names, it’s very difficult to offer practical advice.

  1. (Avoid this step until you’ve addressed 1, 2 and 3). If you end up running the method on the server, consider using this.unblock(), or you will hold off other clients wanting to make use of this method until the active client completes.