-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Handle unhandledrejections in the dev server #9424
Conversation
🦋 Changeset detectedLatest commit: 9b9f51b The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
!preview handle-unhandled |
Snapshots have been released for the following packages:
Publish Log
Build Log
|
function handleUnhandledRejection(rejection: any) { | ||
const error = new AstroError({ | ||
...AstroErrorData.UnhandledRejection, | ||
message: AstroErrorData.UnhandledRejection.message(rejection?.stack || rejection) | ||
}) | ||
logger.error(null, error.message); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit of a edge case, but presumably this should pass through our normal-ish error pipeline so we get a nicely formatted error.
astro/packages/astro/src/core/messages.ts
Line 257 in f8b27b0
export function formatErrorMessage(err: ErrorWithMetadata, showFullStacktrace: boolean): string { |
How does this look in the browser too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can't pass through the normal error pipeline, it happens outside of the context of a request. You could do: setTimeout(() => Promise.reject('foo'), 5000)
and there is no ongoing request, the rejection still happens.
It doesn't currently show up in the browser, do we have a way to send an error from the server to the client outside of a request?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would think that from where you are in the code, you'd be able to send to the websocket since you're so close to the server creation, here's how it works in the rendering:
setTimeout(async () => loader.webSocketSend(await getViteErrorPayload(err)), 200) |
You should just need to send the error payload through the websocket and it should work!»
It can't pass through the normal error pipeline, it happens outside of the context of a request.
If you can't make it go through the entire pipeline, at least formatting the error message would be great:
astro/packages/astro/src/core/messages.ts
Line 257 in f8b27b0
export function formatErrorMessage(err: ErrorWithMetadata, showFullStacktrace: boolean): string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm looking to see if async_hooks can help. https://nodejs.org/api/async_hooks.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think AsyncLocalStorage can maybe allow this, going to give that try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And so it begins... I have many ideas for AsyncLocalStorage!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated the PR and it should work now. Updated with a screenshot of what the browser receives. Would appreciate another review @Princesseuh
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error message looks good to me! 🥳
Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
!preview handle-unhandled |
Snapshots have been released for the following packages:
Publish Log
Build Log
|
incomingRequest: request, | ||
incomingResponse: response, | ||
manifest, | ||
localStorage.run(request, () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing in the request
which acts as the context for the local storage. When an unhandled rejection occurs, we can use this to know which request it was associated with.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First time I see AsyncLocalStorage
in action!
const store = localStorage.getStore(); | ||
if(store instanceof IncomingMessage) { | ||
const request = store; | ||
setRouteError(controller.state, request.url!, error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This marks the route as being in an error state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not 100% satisfied with the stack trace in the error message, but since we don't show cause
super well and it's a bit of a edge case, it's okay, we can improve it later if we get requests.
Changes
.catch()
, will crash the dev server. We can prevent it usingprocess.on('unhandledRejection')
.Testing
Docs
N/A, bug fix