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

promise chain execution affected by whether an error handler is registered #274

Closed
kbullaughey opened this issue Nov 21, 2017 · 9 comments
Closed

Comments

@kbullaughey
Copy link

kbullaughey commented Nov 21, 2017

I originally posted issue emberjs/ember.js#15864 to ember.js, but when I found I could explain the strange behavior purely based on the version of backburner used, perhaps the issue should be here.

The crux of it is that which callbacks are called in a promise chain is affected by whether I've called Ember.onerror or not. It seems that somehow backburner is behaving differently depending on if a callback has been registered, even if it's an empty callback.

If you prefer me to migrate the issue here, I'm happy to. Here's a repo where I distill and illustrate the problem: https://github.com/kbullaughey/ember-effect-of-onerror

@kbullaughey
Copy link
Author

kbullaughey commented Nov 22, 2017

The commit that explains this difference is 4eb0bce and it relates to issue #246.

It seems that in the presence of an error handler thrown errors are caught but not re-thrown. It seems if the main purpose of registering an error handler through Ember.onerror() is for logging, you'd want the behavior to be the same whether or not a handler is registered. I can fix this problem by re-throwing the error as follows:

let onError = getOnError(this.options);

if (onError) {
  try {
    return method.apply(target, args);
  } catch (error) {
    onError(error);
    throw error;  // ADDED THIS LINE
  }
} else {
  return method.apply(target, args);
}

}

Although in the discussion of #246, catching the error in this way in join() was done to make it behave the same as run(). I don't know enough about backburner to know what is the desired behavior.

Thoughts?

@kbullaughey
Copy link
Author

kbullaughey commented Nov 22, 2017

To me it seems swallowing errors when a global error handler is registered is dangerous.

For example, suppose we have methods step1, step1Success, step1Fail, and step2 and put these into a promise chain:

step1().then(bind(null, step1Success), bind(null, step1Fail)).then(step2);

If the promise returned by step1 rejects, causing the step1Fail reject handler to be called, and then this handler in turn throws an exception, step2 will be called. But this will only happen if an global error handler was registered. In the absence of such a handler, step2 will not be called.

If the methods were not part of the runloop:

step1().then(step1Success, step1Fail).then(step2);

Then if step1 rejects, and step1Fail throws an exception, then the step2 will not be executed, just like if there is no global error handler registered.

Thus the behavior with a global error handler is different than you'd expect from either an ordinary promise chain or a promise chain involving the runloop but with no global error handler.

@rwjblue
Copy link
Collaborator

rwjblue commented Nov 22, 2017

Awesome digging @kbullaughey! Thank you for tracking this down so well.

I do believe that #246 does do the correct thing (run and run.join should have the same error semantics).

@rwjblue
Copy link
Collaborator

rwjblue commented Nov 22, 2017

Grr, accidentally submitted that comment before finishing (sorry).

I totally agree that there is a bug here, I was just working out how to detangle things in Ember-land around emberjs/ember.js#14898 which I believe is generally related to the thing you are hitting here.

@kbullaughey
Copy link
Author

I don't necessarily suggest accepting my pull request. I believe it may introduce an inconsistency between run() and join().

@rwjblue
Copy link
Collaborator

rwjblue commented Nov 23, 2017

Thanks for the continued investigation here @kbullaughey. I have been digging at this and related problems most of the day. Should hopefully have some PR's up by EOW...

@rwjblue
Copy link
Collaborator

rwjblue commented Nov 23, 2017

I submitted #277 to address this, mind reviewing?

@kbullaughey
Copy link
Author

It all looks good to me. And I can confirm that it solves the problems I was having.

Though one question, this test has two assertions but assert.expect(1) and I the onError method is not called. Is this intentional? Maybe there's dead code here?

@rwjblue
Copy link
Collaborator

rwjblue commented Nov 23, 2017

Ya, mind fixing that up in a separate PR? Definitely seems confusing at least, most likely a copy paste error...

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