flow-router icon indicating copy to clipboard operation
flow-router copied to clipboard

Meteor methods with client stubs not supported for waitOn()? Promise not resolved Error: Can't set timers inside simulations

Open drone1 opened this issue 9 months ago • 3 comments

I'm having an issue:

  • Version of flow-router-extra you're experiencing this issue: 3.9.0 and 3.10.1
  • Version of Meteor you're experiencing this issue: 2.15
  • Browser name and its version (Chrome, Firefox, Safari, etc.)? Chrome Version 124.0.6367.119 (Official Build) (arm64)
  • Platform name and its version (Win, Mac, Linux)? Mac
  • If you're getting an error or exception, please provide its full stack-trace as plain-text or screenshot
[ostrio:flow-router-extra] [route.wait] Promise not resolved Error: Can't set timers inside simulations
  at withoutInvocation (meteor.js?hash=7dd187e6c4c7dc8731ddaf9d1d993d3c3ba5a732:647:13)
  at bindAndCatch (meteor.js?hash=7dd187e6c4c7dc8731ddaf9d1d993d3c3ba5a732:659:33)
  at Meteor.setTimeout (meteor.js?hash=7dd187e6c4c7dc8731ddaf9d1d993d3c3ba5a732:674:21)
  at subWait (route.js:108:22)
  at route.js:128:11
  at meteor.js?hash=7dd187e6c4c7dc8731ddaf9d1d993d3c3ba5a732:1343:22

This does not work for me:

methods.js (imported on both client and server):

// METEOR METHOD WITH CLIENT STUB
Meteor.methods({
	async 'simulation.test'() {
		if (Meteor.isServer) {
			const slowOperation = () => new Promise(resolve => Meteor.setTimeout(resolve, 1000))
			return await slowOperation()
		}
	}
})

routes.js, imported on the client:

FlowRouter.route('/', {
   		name: 'test',
		waitOn(params, query, ready) {
			return new Promise(async (resolve, reject) => {
				try {
					console.log('calling simulation.test...')
					await Meteor.callAsync('simulation.test')
					console.log('done.')
					resolve()
				} catch (err) {
					reject(err)
				}
			})
		},

		// ...action...
})

Exception thrown, since you are calling Meteor.setTimeout here:

    const subWait = (delay) => {
      timer = Meteor.setTimeout(() => {           // PROBLEM
        if (this.checkSubscriptions(subscriptions)) {
          Meteor.clearTimeout(timer);
          _data = getData();
          if (_resources) {
            whileWaitingAction();
            getResources();
          } else {
            next(current, _data);
          }
        } else {
          wait(24);
        }
      }, delay);
    };

If I change the Meteor method to have no client stub, the exception goes away:

(...routes.js same as above...)

methods.js

if (Meteor.isServer) {
	Meteor.methods({
		async 'simulation.test'() {
			const slowOperation = () => new Promise(resolve => Meteor.setTimeout(resolve, 1000))
			return await slowOperation()
		}
	})
}

Definiing waitOn() as follows instead does NOT seem to cause the exception:

			return new Promise((resolve, reject) => {   // NOTE: No 'async' here
				try {
					console.log('calling simulation.test...')
					Meteor.call('simulation.test', (err, result) => {    // NOTE: Meteor.call rather than 'await Meteor.callAsync'
						console.log('done.')
						resolve()
					})
				} catch (err) {
					reject(err)
				}
			})

Originally I was definiing waitOn() with return new Promise(async (resolve, reject) => ... and calling a ValidatedMethod, which always defines a client stub as far as I can tell, like await myValidatedMethod.callAsync(), which caused this exception.

Would be great if you could support client stubs, but anyway, any suggestions here? Am I doing something unreasonable? Thanks.

drone1 avatar May 10 '24 18:05 drone1