Using this.unblock, what are your experiences?

Hi everyone,

I’ve just started to play around with this.unblock to further improve performance by reducing method call wait times. I’m curious to get the feedback from some of you who probably use it a lot.

The scope of this question is for everyone using Meteor’s default DDP for methods and subscriptions. This relates to all DDP message traffic moving from the server to the client.

Where do you find using this.unblock most useful? Do you use it on the majority of your method calls that don’t have dependants? Do you have an performance gain stats to brag about after implementing it?

I’ve also noticed that there is a package out there that looks interesting as it is listed in the docs for adding this.unblock as an add-on for publications. The package is meteorhacks:unblock (see package on atmosphere here) This package has a lot of installs, so I’m curious if we should be aware of it for long term community maintenance. @storyteller or @filipenevola what do you think about maintaining it?

The following Meteor Cloud/Galaxy APM guide gives a great overview of how to find slow wait times and use this.unblock to free them up and improve the overall response times for methods and publications.

The Trace Explorer in Meteor Cloud APM make is really easy to drill down to the slow wait time and see what what subscriptoins or methods are causing the delay.

https://galaxy-guide.meteor.com/apm-managing-waittime.html

Here is an example of how it’s used:

Meteor.methods({

  longMethodOne() {
    this.unblock();
    Meteor._sleepForMs(1000 * 60 * 60);
    return true;
  },

  async longMethodTwo() {
   //this.unblock(); redundant
   Meteor._sleepForMs(1000 * 60 * 60);
   return true;
  }

});

I mostly use async Meteor calls these days, like longMethodTwo() and return a value to the client using the Meteor.callPromise() approach, so I’m also wondering, is there any difference between how Meteor would handle longMethodOne() vs. longMethodTwo()?

I’ll be doing some more experimenting myself and plan to add some finding below, but I’m just curious if you all have experience to share :grinning:

I found this tread where it seems that using this.unblock on pub/sub had some undesired side effects, so maybe the extra add-on package needs a deeper review.

Yes, we frequently use this.unblock() in Meteor methods in our Meteor apps to avoid unnecessary delays waiting for the previous Meteor method to complete before we can run another one.

Meteor 2.3 will natively support this.unblock() in publications, eliminating the need for the Atmosphere packages meteorhacks:unblock or lamhieu:unblock.

In your example, the only reason you would have to declare longMethodTwo() as async would be if you were calling other async functions within in, which you are not.

2 Likes

We have a custom override for our methods and we call this.unblock() to all of our method calls through the override so we never really type it anymore. Therefore, we have only one expectation that all our client method calls are unblocked. We don’t want the extra overhead of thinking and checking if a method is being unblocked or not.

2 Likes

Hi!
Would you please share some rough example about how to override methods? I’m looking for similar behavior but for a different usecase.

Thanks.

Thanks for the comments/feedback @vlasky and @rjdavid

Looks like this topic has been discussed for a long time in the community. I wanted to include a reference to another discussion I found on this topic with a cool approach from @robfallows for making publications unblock without an added package.

It seems that wrapping a publication with a Meteor.setTimeout of zero might have the same result as unblocking a publication with code changes via packages or updates in Meteor 2.3.

Meteor.setTimeout(() => {
  Meteor.publish('myPublication', function() {
    // ... standard publication code here, e.g.
    return myCollection.find();
  });
}, 0);

And I also found a nice write up he did to help clarify the async understanding for me. It seems that using async methods do produce an equivalent result as this.unblock from what I’m understanding.

Here is the article on the Meteor blog… below is a quote from the conclusion… In my hypothetical example for longMethodTwo() I don’t need this.unblock inside, as it would be redundant.

3.3. If this.unblock() is used (or you’re using async methods), methods may be evaluated out of order — the queue is popped until empty, each method starting up in a new fiber as soon as it’s popped. Methods finish independently of the order in which they were initially present in the queue. This may result in unpredictable interleaving which is a recipe for hard-to-diagnose, race-induced bugs. If you need to take advantage of this approach, you also need to be certain that it’s safe if your methods complete out of order.

It’s cool that this.unblock will work in publications in Meteor 2.3. Great job on the PR @vlasky …It seems that as long as there are not order-based interdependencies in the subscribed data on the client that it would be a good approach.

Thanks for sharing Rob Fallows’s article Fun with Meteor Methods. I was unaware that declaring Meteor methods as async avoided the need for this.unblock().

I wonder what happens if you pass an async function to Meteor.publish(). Would this also avoid the need for this.unblock()?

2 Likes

Implemented it using mixins with validated methods

1 Like

There is a difference. You can use this.unblock() on specific lines of code within your method. Can be useful for optimistic UI implementation for example.

1 Like

I just wanna give a slightly different perspective:

→ We don’t use this.unblock, almost never.

As I understand it, and please correct me if i’m wrong, this only unblocks multiple methods being called by the same user.

As we’re using a “classic” “methods for UI Interactions / Update Requests to the server” / Pub/Sub for the dataflow from the server to the client (Using blaze btw) model this is almost never a thing we’d actually need and would be more of an issue as it’s more “thread-safe” per user to not having multiple methods running in parallel.

Would consider it for long-running methods of course.

But I don’t use it as a general performance booster or somesuch and it wouldn’t do a lot for us.

Multiple requests / method calls by multiple users in parallel are already paralellized by meteor / fibers.

And not having unblocked code gives nice ordering / predictability from the client side as well.

So there you go! Don’t just unblock everything - or do - but know what you’re doing! It might not do a whole lot depending on the use case.

I think it’s important to understand what it’s doing and what it’s for.

7 Likes

We use it by default for all declared Meteor methods + publications. This excludes the Meteor methods automatically declared for client-side db updates. It’s almost never been an issue for us.

1 Like

I think there is some misconception here (quote from the original topic):

I really don’t know how the above code could have the same effect as running this.unblock() (e.g. in Meteor 2.3 or with an external package). This code merely delays the setup of the respective publication, not its execution. @robfallows also hints that when he writes…

[…] if you have many publications and they take a long time to set up, you can set them up asynchronously

The callback of the publication will first be invoked when a client calls Meteor.subscribe, but then the invocation of Meteor.setTimeout won’t play a role anymore.

So unless I’m mistaken, the above “trick” with Meteor.setTimeout isn’t a substitute for this.unblock() in publications.

1 Like

Using unblock in methods seems to work fine, but be cautious with using it in publications. I tried this and realized that it causes Meteor to invalidate and resend all publication data every time you change the input parameters. Without unblock, it will only send the deltas. For my geospatial app, this caused a huge performance degradation. Your mileage might vary.

More details here:

@waldgeist to clarify, when you tested this.unblock() within a publication back in February, were you using the Atmosphere package meteorhacks:unblock or lamhieu:unblock?

I am using lamhieu:unblock. I try to avoid the meteorhacks stuff, as it is unmaintained. Arunoda left the community long time ago.

BTW: You can easily verify my statements using Meteor Dev Tools. Subscribe to a publication with a lot of documents and then change the input parameters, so only a fraction of the documents would have to be deleted or added. Without unblock, you will only receive the deltas. With unblock, all documents will be deleted and re-added afterwards. Which can cause lots of unnecessary data transfer and waiting time. In my app (which is geospatial), it made the map display unusable.

Unfortunately, I only noticed that after a while, so it was very hard to track this down to its actual root cause. I only noticed it because in our Augmented Reality frontend content vanished and popped up again without any reason, which did not happen before. This was caused by the deletions and additions in quick succession.

I am wondering if the new built-in unblock feature in Meteor 2.3 has the same problems?

2 Likes

Based on your observations, it seems it would as it is based on the code in lamhieu:unblock.

1 Like

Very interesting thread!

I’m also aligned with @DanielDornhardt’s comment. I’ve almost never used this.unblock.

There was one specific time where I had to retrieve information from an external database in three different components rendering in parallel. So each component had a method that queried the external db and brought some info, right?. In this case it was pretty evident that things where happening sequentially, extending the overall time needed for the page to be completely ready.

Unblocking these methods made the calls in parallel and the experience was much better (reducing the overall load time to around 1/3 of the blocked/sequential scenario).

I’ve never needed (or thought of) unblocking pubs (I don’t quite understand the pub “setup” hack suggested by Rob) or unblocking methods for any other case in an enterprise app with more than 2 years of development.

I’ll keep an eye on this thread to learn more on the subject (and dive-in in the suggested links)

Thanks!
Regards

2 Likes

In React, with components and state handling, I do not see much need for executing methods that are not in parallel. Imagine loading a modular page with different components each with different method calls.

If you need a method dependent on another method, you can either

  1. call the method inside the other method in the server
  2. use the callback of the method in the client
1 Like

In vanilla JS, either modern or not modern, when we invoke anything that has a callback, we comprehend that it is unpredictable, when it will actually be called.

When we make multiple calls right after each other, each of which has its own callback, we do know that the order in which the individual callbacks will be called is unpredictable. So far no one is surprised, this is just how Javascript works. If we want those to be executed in a particular order, there are multiple simple ways to manage it, for example:

  • the dependent invocation will be made within a callback of the call on which it depends
  • or we can wrap each invocation (with a callback) into a Promise, so we can chain the invocations using Promise.then()

Meteor introduced a sequential method execution order, which is very unusual in Javascript. The creators shouldn’t have done that, I think it was a mistake. This mistake will be exacerbated by this.unblock() which can be used selectively. This way it becomes totally opaque how a sequence of Meteor method calls will be processed. For example:

Meteor.call('methodOne', methodOneParams, methodOneCallback);
Meteor.call('methodTwo', methodTwoParams, methodTwoCallback);

How do you know whether methodTwo will be invoked strictly after methodOne?

The answer is that you can’t possibly know just by assessing the client code. Your only chance to find out is to actually go look methodOne's code and check if this.unblock() is invoked. That’s totally crazy, and leads inevitably to misunderstandings, and that may lead to bugs.

2 Likes

Everyone has interesting views / experience on this :grinning: I’m finding it really helpful. I can see that maybe there are two app architectures approaches emerging. I’ll have to get around to trying both approaches to see what performance differences emerge for me.

I’m seeing:

Approach 1: Use this.unblock rarely (prioritize server performance)

  • Use for known long running methods, usually to 3rd party APIs with unknown performance
  • Order of methods & subs is thoughtfully designed on the client
  • Usually not running all methods & subs in one batch, on page load for example
  • Methods & subs running serially would reduce the peak loads on the server, but it could create long load times on the client (to use an extreme, if 100 things run serially, a big user wait time would be present on the client)

Approach 2: Using this.unblock often (prioritize client performance)

  • Use for all methods & subs because they are often running in parallel, batched per client
  • Order of loading methods & subs have almost no interdependencies
  • Any interdependencies are thoughtfully designed on the server / client
  • Methods & subs running in parallel would probably put more of a spike load on the server per client connection (to use an extreme, if 100 things run at the same time a big performance spike would be seen on the server)
  • If there is plenty of performance overhead on the server (extra $$), the end user will probably experience a very fast app, if the server limits are reached, there could be user issues experienced
  • Probably prioritize bigger containers over “more” containers in production

It seems like there is the room to make choices between 1 & 2 or have a mix. This should be fun to dive into further!

If anyone also wants to share how their basic app stacks look & how their apps are running in production that would probably be helpful to go with more comments. Meteor is so flexible we are probably just seeing a couple of the most common architectures emerge. :comet:

1 Like