graphql-python / graphql-python/graphql-core-legacy

AsyncioExecutor produces hard to debug errors

Open
#126 6 comments 3 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
372
Forks
175
PR merge metrics
No merged PRs in 30d

Description

When an `async` resolver is raising an exception, this exception is not logged and its stack in lost and never printed. The only "report" is the error carried by the `ExecutionResult` but we can only access its type and message, not the actual stack trace.

This is different for sync resolvers (even when using the `AsyncioExecutor`): the exception is printed by `graphql.execution.executor resolve_or_error`.

Below is an example to illustrate the issue:
```python
from graphql.execution.executors.asyncio import AsyncioExecutor
from graphql import GraphQLObjectType, GraphQLField, GraphQLString, GraphQLSchema, graphql

def resolve_hello(root, args, context, info):
raise Exception("wololo")

async def resolve_hello_async(root, args, context, info):
raise Exception("wololo")

QueryType = GraphQLObjectType("Query", fields={
"hello": GraphQLField(GraphQLString, resolver=resolve_hello),
"helloAsync": GraphQLField(GraphQLString, resolver=resolve_hello_async),
})

schema = GraphQLSchema(query=QueryType)

print("Sync execution")

result = graphql(schema, '{ hello }', executor=AsyncioExecutor())
# This will log something like:
#
# An error occurred while resolving field Query.hello
# Traceback (most recent call last):
# File ".../site-packages/graphql/execution/executor.py", line 200, in resolve_or_error
# return executor.execute(resolve_fn, source, args, context, info)
# File ".../site-packages/graphql/execution/executors/asyncio.py", line 50, in execute
# result = fn(*args, **kwargs)
# File "test.py", line 11, in resolve_hello
# raise Exception("wololo")
# Exception: wololo

# As a side note, the produced error have a correct stack trace:
print(result.errors[0].stack) #

print("=" * 10)
print("Async execution")

async_result = graphql(schema, '{ helloAsync }', executor=AsyncioExecutor())
# While producing the same result, it won't log anything, and good luck to know where
# the error comes from.

# This error has None as a stack trace:
print(async_result.errors[0].stack) # None
```

I am a beginner with python async stuff so I won't send a PR, but as a temporary solution I am replacing the `AsyncioExecutor execute` method with something like that:
```python
def execute(self, fn, *args, **kwargs):
result = fn(*args, **kwargs)
if isinstance(result, Future) or iscoroutine(result):
async def hop():
try:
awaited_result = await result
except Exception as e:
logger.exception("Exception in %s", fn)
raise
return awaited_result
future = ensure_future(hop(), loop=self.loop)
# future = ensure_future(result, loop=self.loop)
self.futures.append(future)
return Promise.resolve(future)
return result
```

EDIT: I am using graphene 1.4 and graphql 1.1

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.