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

fix: Clean up hooks code #1407

Merged
merged 1 commit into from Jun 30, 2019
Merged

fix: Clean up hooks code #1407

merged 1 commit into from Jun 30, 2019

Conversation

vonagam
Copy link
Member

@vonagam vonagam commented Jun 18, 2019

Fixes two errors:

  1. finally hooks can possibly run twice for same method call if one of them throws. Also a finally hook if throws activates error hooks, this is in conflict with this comment and also Promise.finally and try/catch/finally convention. Because currently it is like this (1, 2):
try {
  run([...before])();
  method();
  run([...after, ...finally])();
} catch {
  run([...error, ...finally])();
}
  1. An error hook can get a context which is not up to date, if any before hook returns new context object and a service method throws, because errors (1, 2) thrown in a method invocation do no have hook property set (which should contain a last valid hook context), that's why error hooks end up using an initial hook object.

Added fixes and tests for such cases. Also small clean up changes for readability and performance.

A question for future: What are use cases for allowing returning new context object from hook functions where modifying context in place is not as convenient?

@vonagam vonagam force-pushed the fix-clean-hooks branch 3 times, most recently from 35389f8 to d417ff7 Compare June 18, 2019 14:42
@vonagam
Copy link
Member Author

vonagam commented Jun 18, 2019

What about adding finally to the list of hook types?

@daffl daffl merged commit f25c88b into feathersjs:master Jun 30, 2019
@daffl
Copy link
Member

daffl commented Jun 30, 2019

This makes a lot of sense, thank you! That the finally hooks are not documented is somewhat intentional because they were really only intended to be used internally (to send events). For the next major version I'd prefer to go in the direction the Koa style hook system outline in #932 which would allow a finally like this:

app.service('users').hooks({
  create: [
    async (context, next) => {
      const finally = async () => {
        // Finally code here
      }

      try {
        await next();
        await finally();  
      } catch (error) {
        await finally();
        throw error;
      }
    }
  ]
}

A convenience wrapper may also make this shorter.

@vonagam
Copy link
Member Author

vonagam commented Jun 30, 2019

Cool about koa style, prefer it too.

By the way your example snippet has the same problem as this pull request solves for current system: if your finally() function throws it will run twice. Here is how it should be written:

Instead of:

try {
  await next();
  await finally();  
} catch (error) {
  await finally();
  throw error;
}

It should be:

try {
  await next();
} finally {
  await finally();
}

@daffl
Copy link
Member

daffl commented Jun 30, 2019

Ah, totally. That's totally it.

@vonagam vonagam deleted the fix-clean-hooks branch July 2, 2019 18:24
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

Successfully merging this pull request may close these issues.

None yet

2 participants