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

AsyncioExecutor produces hard to debug errors

Offen
#126 6 Kommentare 3 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
Python
Sterne
372
Forks
175
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beschreibung

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

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Rechercherichtung

Beginne in graphql/execution/executors/asyncio.py, insbesondere bei AsyncioExecutor.execute, und vergleiche die Verarbeitung mit graphql.execution.executor resolve_or_error. Reproduziere die Sync- und Async-Resolver-Beispiele aus dem Issue und überprüfe anschließend, dass Async-Ausnahmen mit ihren Stacktraces protokolliert werden und dass der resultierende Fehler seine Stackinformationen beibehält.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
backend-api-design
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
45/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.