Kyll
Kyll

Reputation: 7139

How do I simulate multiple simultaneous slow Meteor publications?

I want to simulate multiple slow subscriptions. The client subscribes to two or more publications at the same time, and the result arrive later.
The goal is to be able to see how network latencies and randomness can affect my application (it bugs because I expected a publication to be ready before another, ...).

Using the following short setup for the publications:

// server/foo.js
Meteor.publish('foo', function() {
  console.log('publishing foo');
  Meteor._sleepForMs(2000);
  console.log('waking up foo');
  this.ready();
});

// server/bar.js is the same with a different name
Meteor.publish('bar', function() {
  console.log('publishing bar');
  Meteor._sleepForMs(2000);
  console.log('waking up bar');
  this.ready();
});

Both publications are slowed down thanks to Meteor._sleepForMs as seen in this amazing answer.

The client then subscribes to each publication:

Meteor.subscribe('bar'); // /client/bar.js
Meteor.subscribe('foo'); // /client/foo.js

From there I expected to see both 'publishing' logs first, then both 'waking up'.

However, this appears in the console:

15:37:45? publishing bar
15:37:47? waking up bar
15:37:47? publishing foo
15:37:49? waking up foo

(I removed some irrelevant fluff like the day)

So obviously it runs in a synchronous fashion. I thought that two things can cause that: the server waitForMs which would entirely block the server (fairly weird), or the client subscription design.

To make sure that it wasn't the server I added a simple heartbeat:
Meteor.setInterval(function() { console.log('beep'); }, 500);

And it did not stop beeping, so the server isn't fully blocked.

I thus suspect that the issue lies within the client subscription model, which maybe waits for the subscription to be ready before calling another..?

Thus, two questions:

Upvotes: 1

Views: 334

Answers (3)

xamfoo
xamfoo

Reputation: 151

Why doesn't my experiment run the way I wanted it to?

Meteor._sleepForMs is blocking from the way it is implemented:

Meteor._sleepForMs = function (ms) {
  var fiber = Fiber.current;
  setTimeout(function() {
    fiber.run();
  }, ms);
  Fiber.yield();
};

Calling it prevents the next line from executing inside the fiber until the duration passes. However, this does not block the Node server from handling other events (i.e. executing another publication) due to the way fiber works.

Here is a talk about Fibers in Meteor: https://www.youtube.com/watch?v=AWJ8LIzQMHY

How should I modify it to achieve my desired goal (multiple slow publications) ?

Try using Meteor.setTimeout to simulate latency asynchronously.

Meteor.publish('foo', function() {
  console.log('publishing foo');

  var self = this;

  Meteor.setTimeout(function () {
    console.log('waking up foo');
    self.ready();
  }, 2000);
});

Upvotes: 1

Curtis
Curtis

Reputation: 681

Meteor processes DDP messages (which include subscriptions) in a sequence. This ensures that you can perform some action like deleting an object and then inserting it back in the correct order, and not run into any errors.

There is support for getting around this in Meteor.methods using this.unblock() to allow the next available DDP message to process without waiting for the previous one to finish executing. Unfortunately this is not available for Meteor.publish in the Meteor core. You can see discussion (and some workarounds) about this issue here: https://github.com/meteor/meteor/issues/853

There is also a package that adds this functionality to publications:

https://github.com/meteorhacks/unblock/

Upvotes: 1

Elie Steinbock
Elie Steinbock

Reputation: 5088

I believe it's because the publications are blocking.

You can use meteorhacks:unblock to unblock publications: https://atmospherejs.com/meteorhacks/unblock

It could be a good idea to use this.unblock() at the start of every publication (once you've added meteorhacks:unblock).

Upvotes: 0

Related Questions