Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
drone1 opened this issue May 10, 2024 · 3 comments

Comments

@drone1
Copy link

drone1 commented May 10, 2024

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.

@dr-dimitru
Copy link
Member

@drone1 generally I'd say — Use stubs only for user-interaction actions.
What expected behavior you assuming when waitOn receives stub then server response, page/route reload?

@drone1
Copy link
Author

drone1 commented May 12, 2024

Hey @dr-dimitru!

Maybe it would be helpful to throw an exception before Meteor.setTimeout() if in simulation? I'm not sure if this is an easy one-liner, since the code is running outside of a method, you may not be able to check isSimulation as you can within a Meteor method. Maybe not worth it.

The behavior I'd expect is to not get an exception thrown by Meteor.setTimeout() being called, and the code moving along as expected as data comes back from the server.

The Meteor docs recommend client stubs for all methods IIRC so I'd gotten into the habit of doing that.

Thanks for getting back.

@dr-dimitru
Copy link
Member

@drone1 Do you want to push a PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants