Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Discussion: decoupling async data loading from async graph resolution

Aperta
#171 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
25/100
Tipo di issue
Funzionalità
Chiarezza
Da chiarire
Stato di attività
Ferma
Stack tecnologico
graphql, python

Direzione di ricerca

Inizia con l’esempio asyncio main() e la chiamata graphql(schema, query, context_value=context). Traccia come vengono pianificati i resolver async EStopHMI e JogHMI e come viene gestito il loro awaitable. L’issue richiede un design che separi la scoperta dei dati foglia, il recupero e la risoluzione del risultato finale; non viene indicato alcun file di implementazione o test specifico.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

TLDR: I would like graph-core to tell me what "leaf" nodes from my query need returned. Allow me to fetch the data through whatever method I deem efficient. Then I would like graph-core to take care of returning the data. The current asyncio implementation, seems to fundamentally not work for this.

I've been digging in deep on a graphql-core build recently and have stumbled across this interesting problem. If I've missed a key feature of the library here, than please point it out.

To me, the ideal way to use the core library is to:

  1. Use graph-core to decide what data to retrieve.
  2. Use a separate data loading engine to read the data.
  3. Use graph-core to return the data.

Its interesting to see where this problem fits in as either a graphe-core-3 issue, needing a feature, or a graphql issue. The essential catch is this, it's very hard to determine when the graph-core resolution has finished deciding what leaves from the graph need fetched. Here's an example to illustrate the point.

##########################################################
## TEST GRAPHE SCHEMA BASED ON ASYNCIO ######################
##########################################################
from graphql import (
    GraphQLBoolean, graphql, GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLString)
import logging
import asyncio

_logger = logging.getLogger('GrapheneDeferralTest')
_logger.setLevel('DEBUG')

query = """
{
    ioHMIControls {
        EStopHMI,
        JogHMI,
    }
}
"""

async def resolve_EStopHMI(parent, info):
    _id = '_EStopHMI_id'
    info.context['node_ids'][_id] = None
    await info.context['awaitable']
    return info.context['node_ids'][_id]
EStopHMI = GraphQLField(
    GraphQLBoolean,
    resolve=resolve_EStopHMI
)

async def resolve_JogHMI(parent, info):
    _id = '_JogHMI_id'
    info.context['node_ids'][_id] = None
    await info.context['awaitable']
    return info.context['node_ids'][_id]
JogHMI = GraphQLField(
    GraphQLBoolean,
    resolve=resolve_EStopHMI
)


def resolve_ioHMIControls(parent, info):
    return ioHMIControls
ioHMIControls = GraphQLObjectType(
    name='ioHMIControls',
    fields={
        'EStopHMI': EStopHMI,
        'JogHMI':JogHMI,
    }
)

def resolve_GlobalVars(parent, info):
    return GlobalVars
GlobalVars = GraphQLObjectType(
    name='GlobalVars',
    fields={
        'ioHMIControls': GraphQLField(ioHMIControls, resolve=resolve_ioHMIControls)
    }
)

async def simulate_fetch_data(_ids):
    print(_ids)
    await asyncio.sleep(1)
    return {k:True for k in _ids.keys()}
    
async def main():
    # Objective:
    #     1. Have graph determine what data I need by partially resolving
    #     2. Pause graph resolution.
    #     3. Collect data into a `data_loader` object.
    #     4. Retrieve data via `data_loader` object.
    #     5. Resume graph resolution with loaded data.

    # 3. collect ids of data fields into a dict
    _ids = {}

    #2. pause graph resolution by awaitn a future
    future = asyncio.Future()
    context = {
        'node_ids': _ids,
        'awaitable': future,
    }
    schema = GraphQLSchema(query=GlobalVars)

    # 1. Determine WHAT data to return
    resove_graph_task = asyncio.create_task(graphql(schema, query, context_value=context))

    # ?
    # There is no way to detect that resolve_graph_task
    # has finished fillin _ids dict with id values.

    # 4. Fetch the data
    fetch_data_task = asyncio.create_task(simulate_fetch_data(_ids))

    # ? 
    # This await doesn't work in this order or any order
    # becaus of the interdependancy of both tasks, coupled with 
    # the mechanics of asyncio.
    await fetch_data_task

    # 5. Resume graph resolution with retrieved data.
    future.set_result(0)

    # ? 
    # return the data from the graph, as a graph result. 
    # problem, is that the data is not there due to 
    # interdependancy between await tasks. 
    result = await resove_graph_task
    print(result)

if __name__ == '__main__':
    asyncio.run(main())

Results

{}
ExecutionResult(data={'ioHMIControls': {'EStopHMI': None, 'JogHMI': None}}, errors=None)

The example is a little long, but I wanted it to be sufficiently complex. The gist is that there is no way in the current asyncio implementation to determine that: all resolvers have been reached.

Looking at the implementations we could use some advanced event systems to manage this, but it would be a bit of work. Another possible solution could be to allow resolvers to return coroutines and put off type checking till those coroutines are themselves resolved. I think, this may be the most elegant method.

Thoughts?

Lingua principale
Python
Stelle
531
Fork
147
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di graphql-python/graphql-core

Tutte le issue di graphql-python/graphql-core

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.