Graphene: Graphql schema probably not suited for parallel execution

Created on 6 Jul 2016  路  7Comments  路  Source: graphql-python/graphene

This is probably a minor issue as it occurs only on server startup.

I noticed that my django view (with heavy use of relay), when rendered right after django startup, tends to throw a variety of graphql errors.
It came out only with relay (that is - when multiple graphql queries were sent one by one).

After diving into the code I think I more or less analyzed the issue. GraphQLView reuses the same schema (graphene.core.schema.Schema) for execution. That schema has self._types dictionary, which is constructed only once.

  • When more than one thread interfere during initial _types construction, Type {} already registered with other object type errors are thrown inside register method.

That schema also creates graphql.core.type.schema.GraphqlSchema. I'm not sure how this is possible, as every time schema is accessed, a new instance is created, but here again looks like

  • thread interference leads to errors: Schema must contain unique named types but contains multiple types named {} in type_map_reducer function.

Below an example of an error. I don't paste all of them, but that is a good example, as many of them are related to automatically created Connection types, which, I guess, are created independently by separate threads traversing type tree and, so, are not the same types although they do have the same name (which I checked).

Internal Server Error: /graphql/api/
Traceback (most recent call last):
  File "/home/isivi/.local/lib/python2.7/site-packages/django/core/handlers/base.py", line 149, in get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/isivi/.local/lib/python2.7/site-packages/django/core/handlers/base.py", line 147, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/isivi/.local/lib/python2.7/site-packages/django/views/generic/base.py", line 62, in view
    self = cls(**initkwargs)
  File "/home/isivi/.local/lib/python2.7/site-packages/graphene/contrib/django/views.py", line 10, in __init__
    schema=schema.schema,
  File "/home/isivi/.local/lib/python2.7/site-packages/graphene/core/schema.py", line 90, in schema
    subscription=self.T(self.subscription))
  File "/home/isivi/.local/lib/python2.7/site-packages/graphene/core/schema.py", line 22, in __init__
    super(GraphQLSchema, self).__init__(*args, **kwargs)
  File "/home/isivi/.local/lib/python2.7/site-packages/graphql/core/type/schema.py", line 40, in __init__
    self._type_map = self._build_type_map()
  File "/home/isivi/.local/lib/python2.7/site-packages/graphql/core/type/schema.py", line 89, in _build_type_map
    type_map = type_map_reducer(type_map, type)
  File "/home/isivi/.local/lib/python2.7/site-packages/graphql/core/type/schema.py", line 129, in type_map_reducer
    reduced_map = type_map_reducer(reduced_map, getattr(field, 'type', None))
  File "/home/isivi/.local/lib/python2.7/site-packages/graphql/core/type/schema.py", line 129, in type_map_reducer
    reduced_map = type_map_reducer(reduced_map, getattr(field, 'type', None))
  File "/home/isivi/.local/lib/python2.7/site-packages/graphql/core/type/schema.py", line 129, in type_map_reducer
    reduced_map = type_map_reducer(reduced_map, getattr(field, 'type', None))
  File "/home/isivi/.local/lib/python2.7/site-packages/graphql/core/type/schema.py", line 129, in type_map_reducer
    reduced_map = type_map_reducer(reduced_map, getattr(field, 'type', None))
  File "/home/isivi/.local/lib/python2.7/site-packages/graphql/core/type/schema.py", line 121, in type_map_reducer
    field_map = type.get_fields()
  File "/home/isivi/.local/lib/python2.7/site-packages/graphql/core/type/definition.py", line 194, in get_fields
    self._field_map = define_field_map(self, self._fields)
  File "/home/isivi/.local/lib/python2.7/site-packages/graphql/core/type/definition.py", line 207, in define_field_map
    field_map = field_map()
  File "/home/isivi/.local/lib/python2.7/site-packages/graphene/core/classtypes/base.py", line 131, in fields_internal_types
    return schema.T(cls._meta.fields_group_type)
  File "/home/isivi/.local/lib/python2.7/site-packages/graphene/core/schema.py", line 61, in T
    internal_type = _type.internal_type(self)
  File "/home/isivi/.local/lib/python2.7/site-packages/graphene/core/types/base.py", line 152, in internal_type
    return OrderedDict(self.iter_types(schema))
  File "/usr/lib/python2.7/collections.py", line 57, in __init__
    self.__update(*args, **kwds)
  File "/usr/lib/python2.7/_abcoll.py", line 568, in update
    for key, value in other:
  File "/home/isivi/.local/lib/python2.7/site-packages/graphene/core/types/field.py", line 182, in iter_types
    yield self.get_named_type(schema, field)
  File "/home/isivi/.local/lib/python2.7/site-packages/graphene/core/types/base.py", line 146, in get_named_type
    return name, schema.T(type)
  File "/home/isivi/.local/lib/python2.7/site-packages/graphene/core/schema.py", line 61, in T
    internal_type = _type.internal_type(self)
  File "/home/isivi/.local/lib/python2.7/site-packages/graphene/core/types/field.py", line 102, in internal_type
    type = schema.T(self.get_type(schema))
  File "/home/isivi/.local/lib/python2.7/site-packages/graphene/core/schema.py", line 64, in T
    self.register(_type)
  File "/home/isivi/.local/lib/python2.7/site-packages/graphene/core/schema.py", line 99, in register
    type_name)
AssertionError: Type EmployerTypeTileNodeDefaultConnection already registered with other object type

Most helpful comment

@ekampf This issue is hard to fix with the current architecture implementation. However I'm assuring that in 1.0 version no problems like that will happen.
A testcase that replicates the issue could be very helpful too :)

All 7 comments

馃憤 (happens on my end on GAE too)

@syrusakbary any idea regarding this issue? happens to us a lot on Google AppEngine...

@ekampf This issue is hard to fix with the current architecture implementation. However I'm assuring that in 1.0 version no problems like that will happen.
A testcase that replicates the issue could be very helpful too :)

Ill try to report with a test

We are seeing the Schema must contain unique named types but contains multiple types named {} in type_map_reducer a lot running with the Django dev server. Testing with python manage.py runserver --nothreading now.

This parallel execution issue should no longer exist with the current reimplementation (master branch, 1.0.dev version in PyPI).

Please reopen the issue if the problem is not mitigated when using the dev version.

Was this page helpful?
0 / 5 - 0 ratings