zino-hofmann / graphql-flutter

A GraphQL client for Flutter, bringing all the features from a modern GraphQL client to one easy to use package.
https://zino-hofmann.github.io/graphql-flutter
MIT License
3.23k stars 613 forks source link

IOS Subscription problem without stack trace #1357

Closed davidsarosi92 closed 1 year ago

davidsarosi92 commented 1 year ago

Describe the issue

I have a problem, but stack trace is empty - It's hard to describe.

Work on subscription function in flutter. I use the Subscription in my widget. It's working properly on android. It's awesome! :) But on IOS at the first build it's fine - subscription is okay yet. At next build cannot connect to backend. (I think build, handshake, connect, build widget and die but build, handshake, connect, disconnect, build widget sometimes working). The problem only affects IOS. I work on Django, Channels and Strawberry GraphQL.

To Reproduce

  1. Open app
  2. Navigate to Subscription widget
  3. Go back
  4. Navigate to Subscription widget - It's not working on IOS, cannot subscribe again. It should work on IOS too. Stack trace is empty.

Expected behavior

Similar operation on Android and IOS.

Additional context

Flutter 3.10.5 • channel stable • https://github.com/flutter/flutter.git Framework • revision 796c8ef792 (4 weeks ago) • 2023-06-13 15:51:02 -0700 Engine • revision 45f6e00911 Tools • Dart 3.0.5 • DevTools 2.23.1

Getx - State manager. get: ^4.6.5)

Django 4.2.2 and 4.2.3 strawberry-graphql-django 0.9.5 and 0.10.6 Channels 4.0.0 Broker is RabbitMQ

Backend log: ` | Fatal error: protocol.data_received() call failed.

| protocol: <carehare._protocol.Protocol object at 0xffff6edd6690> | transport: <_SelectorSocketTransport fd=17 read=polling write=<idle, bufsize=0>> | Traceback (most recent call last): | File "/usr/local/lib/python3.11/asyncio/selector_events.py", line 1009, in _read_readydata_received | self._protocol.data_received(data) | File "/usr/local/lib/python3.11/site-packages/carehare/_protocol.py", line 118, in data_received | self._handle_buffer_frames() | File "/usr/local/lib/python3.11/site-packages/carehare/_protocol.py", line 170, in _handle_buffer_frames | self._handle_frame_or_crash(channel_id, frame) | File "/usr/local/lib/python3.11/site-packages/carehare/_protocol.py", line 184, in _handle_frame_or_crash | self.accept_frame(frame, channel_id) | File "/usr/local/lib/python3.11/site-packages/carehare/_protocol.py", line 212, in accept_frame | return self._accept_frame_after_handshake(frame, channel_id) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | File "/usr/local/lib/python3.11/functools.py", line 946, in _method | return method.get__(obj, cls)(*args, *kwargs) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | File "/usr/local/lib/python3.11/site-packages/carehare/_protocol.py", line 220, in _accept_frame_after_handshake | channel.accept_frame(frame) | File "/usr/local/lib/python3.11/functools.py", line 946, in _method | return method.get(obj, cls)(args, **kwargs) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | File "/usr/local/lib/python3.11/site-packages/carehare/_exchangechannel.py", line 52, in | self._delivering.pop(tag).set_result(None) | asyncio.exceptions.InvalidStateError: invalid state `

Device / execution context

IPhone 14 Pro Max (16.4 IOS) (emulated) - Second subscription problem Android SDK 33 - working properly

vincenzopalazzo commented 1 year ago

This is hard to reproduce any helps?

davidsarosi92 commented 1 year ago

Okay, I try, so My backends subscription is:

@strawberry.subscription
    async def inventory_count_header(self, info: Info, inventory_count_header_id: int) -> AsyncGenerator[
        InventoryCountHeaderWithInventoryItemsType, None]:
        ...

        ws = info.context.ws
        channel_layer = ws.channel_layer
        group_name = ...

        await channel_layer.group_add(group_name, ws.channel_name)

        await channel_layer.group_send(
            group_name,
            {
                'type': ...,
                'operation': ...,
                'id': ...,
            },
        )

        async for message in ws.channel_listen(..., groups=[group_name]):
            operation: Operation = message['operation']

            ...

            yield result

and on flutter:

...

class InventoryCountHeaderWidget extends InventoryCountHeaderTabWidget {
  const InventoryCountHeaderWidget({super.key, required this.inventoryCountHeaderId});
  final int inventoryCountHeaderId;

  @override
  Widget build(BuildContext context) {
    return GetBuilder<InventoryCountHeaderController>(builder: (controller) {
      return Subscription(
          options: SubscriptionOptions(
            document: controller.inventorySubscription(),
            variables: {'inventoryCountHeaderId': inventoryCountHeaderId},
          ),
          builder: (result) {
            Widget w;
            if (result.hasException) {
              w = ...;
            }
            else if(result.data?['inventoryCountHeader'] == null) {
              w = ...;
            }
            else if(result.data?['inventoryCountHeader'] != null && ...) {
                w = ...;
            }
            else {
              w = ...;
            }

            return w;
    });
  }
}

I use GetX Statemanager.

  1. Navigate to InventoryCountHeaderWidget, it's working. I get data from subs.
  2. I go back (Get.back())
  3. Navigate again to InventoryCountHeaderWidget and it cannot reconnect to subs (I think InventoryCountHeaderWidget stay in memory maybe stay connected and reload not working properly)

Seems connection is alive, result is: QueryResult(source: QueryResultSource.loading, data: null, context: Context({}), exception: null, timestamp: 2023-07-13 09:21:49.702098) but nothing more. Its stucked - Can not work backend with current connection. - I think its consequence from backend, but there are something in after first build on IOS.

I know it's not much, but for now I'm also groping in the dark without an error message.

davidsarosi92 commented 1 year ago

I close the ticket, because I changed the channel layer and now it's working with android and ios. Strange, but I think it can be a solution.

Thank you for your time!

BraveEvidence commented 5 months ago

Can you tell what you mean by channel layer?