Graphcool / graphcool-framework

Apache License 2.0
1.77k stars 131 forks source link

Better handling of exceptions in top-level function (faas) code #512

Open jesstelford opened 6 years ago

jesstelford commented 6 years ago

This relates to issues: #482, #442, https://github.com/graphcool/prisma/issues/1265, and probably others.

Any errors thrown in top-level code of a function cause cryptic error messages such as:

What works

This correctly shows an error in graphcool logs

export default async () => {
  throw new Error('whoops!');
}
$ graphcool logs --tail
2018-04-06T06:22:48.858Z 526ms FAILURE {
  "error": "Function returned invalid status code: 0. Raw body: {\"logs\":[{\"stdout\":\"\"},{\"stderr\":\"\"},{\"error\":\"{\\\"name\\\":\\\"Error\\\",\\\"message\\\":\\\"whoops!\\\",\\\"stack\\\":\\\"Error: whoops!\\\\n    at Object.<anonymous> (/var/faas/functions/.../func.js:2:19)\\\\n    [.. SNIP ..]\\\"}\"}],\"response\":{\"error\":\"Function did not return a valid response. Check your function code / logs.\"}}"
}
$ docker logs local_localfaas_1 -f
{"stdout":"","stderr":"","error":"{\"name\":\"Error\",\"message\":\"whoops!\",\"stack\":\"Error: whoops!\\n    at Object.<anonymous> (/v
ar/faas/functions/.../func.js:52:19)\\n    [.. SNIP ..]\"}"}
Function invocation summary for project cjfkebttn000401812ew1k8f5 and function twitterAuthentication:
        Duration: 429ms
        Success: false
        Function return value: ''
        Error: '{"name":"Error","message":"whoops!","stack":"Error: whoops!\n    at Object.<anonymous> (/var/faas/functions/.../func.js:52:19)\n    [.. SNIP ..]'
        Process stdout: ''
        Process stderr: ''

What doesn't work

This does not show a useful error

throw new Error('an error outside the function!');
export default async () => {
  return { data: { message: 'success!' } };
}
$ graphcool logs --tail
018-04-06T06:27:55.830Z 516ms FAILURE {
  "error": "Function returned invalid status code: 0. Raw body: Server responded with 500"
}
$ docker logs local_localfaas_1 -f
No content to map due to end-of-input
 at [Source: ; line: 1, column: 0]

Suggested Fix

When loading the function source into node, catch errors then, not just when the function itself is executed.

I was unable to find where the code is that handles this part, unfortunately. So in lieu of a PR, here is a workaround:

The workaround

Wrap all your code outside the function in a try/catch, then only throw the error once inside the function:

let topLevelError;
try {
  // any code before the function
} catch (error) {
  topLevelError = error;
}
export default async () => {
  if (topLevelError) {
    throw topLevelError;
  }
  return { data: { message: 'success!' } };
}
marktani commented 6 years ago

Thanks a lot for sharing your insights, @jesstelford. I'd be very curious to see if this is the underlying issue for the many reports about the "Function returned invalid status code: 0. Raw body: Server responded with 500" error 🙂

jesstelford commented 6 years ago

Let me know if I can help in any other way 👍