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(nextjs): Delay error propagation until withSentry is done #4027

Merged
merged 10 commits into from
Nov 15, 2021

Conversation

lobsterkatie
Copy link
Member

@lobsterkatie lobsterkatie commented Oct 5, 2021

In our nextjs API route wrapper withSentry, we capture any errors thrown by the original handler, and then once we've captured them, we rethrow them, so that our capturing of them doesn't interfere with whatever other error handling might go on. Until recently, that was fine, as nextjs didn't actually propagate the error any farther, and so it didn't interfere with our processing pipeline and didn't prevent res.end() (on which we rely for finishing the transaction and flushing events to Sentry) from running.

However, Vercel released a change which caused said errors to begin propagating if the API route is running on Vercel. (Technically, it's if the server is running in minimal mode, but all API handlers on vercel do.) A side effect of this change is that when there's an error, res.end() is no longer called. As a result, the SDK's work is cut short, and neither errors in API route handlers nor transactions tracing such routes make it to Sentry.

This fixes that, by moving the work of finishing the transaction and flushing events into its own function and calling it not only in res.end() but also before we rethrow the error.

(Note: In the cases where there is an error and the server is not running in minimal mode, this means that function will be hit twice, but that's okay, since the second time around it will just no-op, since transaction.finish() bails immediately if the transaction is already finished, and flush() returns immediately if there's nothing to flush.)

H/t to @jmurty for his work in #4044, which helped me fix some problems in my first approach to solving this problem.

Fixes #3917.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 5, 2021

size-limit report

Path Size
@sentry/browser - CDN Bundle (gzipped) 22.47 KB (0%)
@sentry/browser - Webpack 23.35 KB (0%)
@sentry/react - Webpack 23.39 KB (0%)
@sentry/browser + @sentry/tracing - CDN Bundle (gzipped) 29.92 KB (0%)

Copy link
Contributor

@iker-barriocanal iker-barriocanal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The approach looks good to me.

@joshsny
Copy link

joshsny commented Nov 4, 2021

Thank you for this PR 🙏

Is this likely to get merged soon? This is a big issue right now, with no monitoring on our production apps routes deployed to Vercel.

If not, it would be great to update the docs of @sentry/nextjs saying that it does not work on Vercel.

@lobsterkatie lobsterkatie force-pushed the kmclb-nextjs-fix-api-error-propagation branch from 5d1ad31 to 1bb2edb Compare November 9, 2021 14:33
@lobsterkatie lobsterkatie marked this pull request as ready for review November 9, 2021 14:46
Copy link
Contributor

@iker-barriocanal iker-barriocanal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking because of an infinte loop in a test.

@lobsterkatie lobsterkatie force-pushed the kmclb-nextjs-fix-api-error-propagation branch from 1bb2edb to 5c89c28 Compare November 11, 2021 00:37
const captureExceptionSpy = jest.spyOn(Sentry, 'captureException').mockImplementation(jest.fn());
const loggerSpy = jest.spyOn(utils.logger, 'log');
const flushSpy = jest.spyOn(Sentry, 'flush').mockImplementation(async () => {
// simulate the time it takes time to flush all events
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// simulate the time it takes time to flush all events
// simulate the time it takes to flush all events

@lobsterkatie
Copy link
Member Author

Discussed IRL - agreed to merge this.

@lobsterkatie lobsterkatie merged commit fb66a78 into master Nov 15, 2021
@lobsterkatie lobsterkatie deleted the kmclb-nextjs-fix-api-error-propagation branch November 15, 2021 16:46
lobsterkatie added a commit that referenced this pull request Nov 15, 2021
In our nextjs API route wrapper `withSentry`, we capture any errors thrown by the original handler, and then once we've captured them, we rethrow them, so that our capturing of them doesn't interfere with whatever other error handling might go on. Until recently, that was fine, as nextjs didn't actually propagate the error any farther, and so it didn't interfere with our processing pipeline and didn't prevent `res.end()` (on which we rely for finishing the transaction and flushing events to Sentry) from running.

However, Vercel released a change[1] which caused said errors to begin propagating if the API route is running on Vercel. (Technically, it's if the server is running in minimal mode, but all API handlers on vercel do.) A side effect of this change is that when there's an error, `res.end()` is no longer called. As a result, the SDK's work is cut short, and neither errors in API route handlers nor transactions tracing such routes make it to Sentry.

This fixes that, by moving the work of finishing the transaction and flushing events into its own function and calling it not only in `res.end()` but also before we rethrow the error.

(Note: In the cases where there is an error and the server is not running in minimal mode, this means that function will be hit twice, but that's okay, since the second time around it will just no-op, since `transaction.finish()` bails immediately if the transaction is already finished, and `flush()` returns immediately if there's nothing to flush.)

H/t to @jmurty for his work in #4044, which helped me fix some problems in my first approach to solving this problem.

Fixes #3917.

[1] vercel/next.js#26875
onurtemizkan pushed a commit that referenced this pull request Dec 19, 2021
In our nextjs API route wrapper `withSentry`, we capture any errors thrown by the original handler, and then once we've captured them, we rethrow them, so that our capturing of them doesn't interfere with whatever other error handling might go on. Until recently, that was fine, as nextjs didn't actually propagate the error any farther, and so it didn't interfere with our processing pipeline and didn't prevent `res.end()` (on which we rely for finishing the transaction and flushing events to Sentry) from running.

However, Vercel released a change[1] which caused said errors to begin propagating if the API route is running on Vercel. (Technically, it's if the server is running in minimal mode, but all API handlers on vercel do.) A side effect of this change is that when there's an error, `res.end()` is no longer called. As a result, the SDK's work is cut short, and neither errors in API route handlers nor transactions tracing such routes make it to Sentry.

This fixes that, by moving the work of finishing the transaction and flushing events into its own function and calling it not only in `res.end()` but also before we rethrow the error.

(Note: In the cases where there is an error and the server is not running in minimal mode, this means that function will be hit twice, but that's okay, since the second time around it will just no-op, since `transaction.finish()` bails immediately if the transaction is already finished, and `flush()` returns immediately if there's nothing to flush.)

H/t to @jmurty for his work in #4044, which helped me fix some problems in my first approach to solving this problem.

Fixes #3917.

[1] vercel/next.js#26875
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.

@sentry/nextjs not reporting errors from API (serverless) endpoints in Vercel
3 participants