Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 Bug Report: Subscribing Multiple Times with a Single Realtime Instance Results in Null Subscription #156

Closed
2 tasks done
stnguyen90 opened this issue Jun 20, 2023 · 17 comments
Assignees
Labels
bug Something isn't working

Comments

@stnguyen90
Copy link
Contributor

stnguyen90 commented Jun 20, 2023

👟 Reproduction steps

  1. Instantiate a Realtime instance
  2. Subscribe to a channel
  3. Subscribe to another channel

👍 Expected behavior

You get 2 separate working subscriptions

👎 Actual Behavior

log:

subscription: null

The subscriptions don't receive any events.

It looks like the 2nd subscribe closes the websocket, which triggers:

_channels.clear();
_closeConnection();

The _closeConnection() results in the _lastUrl being set to null:

and the _channels.clear() prevents future events from being dispatched properly:

if (_channels[channel] != null) {
for( var stream in _channels[channel]!) {
stream.sink.add(message);
}
}

🎲 Appwrite version

Different version (specify in environment)

💻 Operating system

Linux

🧱 Your Environment

Tested with SDK version 9.0.0 and Appwrite version 1.3.4. For some reason, this only happens on mobile and not on flutter web.

👀 Have you spent some time to check if this issue has been raised before?

  • I checked and didn't find similar issue

🏢 Have you read the Code of Conduct?

@stnguyen90 stnguyen90 added the bug Something isn't working label Jun 20, 2023
@stnguyen90
Copy link
Contributor Author

For now, the best thing to do is to use a separate Realtime instance for each subscription.

@lohanidamodar
Copy link
Member

@stnguyen90 what is the behavior with other SDKs?

@stnguyen90
Copy link
Contributor Author

@lohanidamodar, it works fine in other SDKs. You can use 1 realtime instance and make multiple subscribe calls. The problem with our Flutter SDK is how we handle reconnects.

@rvndsngwn
Copy link

Same issue with me

@Schrolli91
Copy link

Same here.
Is there any milestone, when this will be fixed?

@puntiz
Copy link

puntiz commented Nov 10, 2023

This needs addressing, really handicaps one of the most useful features.

@moshOntong-IT
Copy link

Same here, what is the status of this issue?

@Sokratesli
Copy link

same here. Thank you for the work.

@lohanidamodar
Copy link
Member

Hey, we have a work in progress fix for this issue, if you could test the SDK from this branch and let us know that would be great
https://github.com/appwrite/sdk-for-flutter/tree/fix-realtime-multiple-subscription

dependencies:
	appwrite:
		git:
			url: https://github.com/appwrite/sdk-for-flutter
			ref: fix-realtime-multiple-subscription

@rvndsngwn
Copy link

Hi @lohanidamodar

I have just tested the SDK from the fix-realtime-multiple-subscription branch and now multiple subscriptions are working. Your help is greatly appreciated.

@lohanidamodar
Copy link
Member

Hi @lohanidamodar

I have just tested the SDK from the fix-realtime-multiple-subscription branch and now multiple subscriptions are working. Your help is greatly appreciated.

Thank you for your validation. Will work to get it released soon.

@Andree98
Copy link

Hey, we have a work in progress fix for this issue, if you could test the SDK from this branch and let us know that would be great https://github.com/appwrite/sdk-for-flutter/tree/fix-realtime-multiple-subscription

dependencies:
	appwrite:
		git:
			url: https://github.com/appwrite/sdk-for-flutter
			ref: fix-realtime-multiple-subscription

I tried this patch and an error occurs when restarting the realtime stream whenever it closes

Here's the stacktrace

Concurrent modification during iteration: _Map len:2.
      #0      _CompactIterator.moveNext (dart:collection-patch/compact_hash.dart:714:7)
      #1      RealtimeMixin._createSocket.<anonymous closure> (package:appwrite/src/realtime_mixin.dart:88:49)
      #2      _rootRun (dart:async/zone.dart:1391:47)
      #3      _CustomZone.run (dart:async/zone.dart:1301:19)
      #4      _CustomZone.runGuarded (dart:async/zone.dart:1209:7)
      #5      _BufferingStreamSubscription._sendDone.sendDone (dart:async/stream_impl.dart:392:13)
      #6      _BufferingStreamSubscription._sendDone (dart:async/stream_impl.dart:402:7)
      #7      _BufferingStreamSubscription._close (dart:async/stream_impl.dart:291:7)
      #8      _ForwardingStream._handleDone (dart:async/stream_pipe.dart:99:10)
      #9      _ForwardingStreamSubscription._handleDone (dart:async/stream_pipe.dart:161:13)
      #10     _rootRun (dart:async/zone.dart:1391:47)
      #11     _CustomZone.run (dart:async/zone.dart:1301:19)
      #12     _CustomZone.runGuarded (dart:async/zone.dart:1209:7)
      #13     _BufferingStreamSubscription._sendDone.sendDone (dart:async/stream_impl.dart:392:13)
      #14     _BufferingStreamSubscription._sendDone (dart:async/stream_impl.dart:402:7)
      #15     _BufferingStreamSubscription._close (dart:async/stream_impl.dart:291:7)
      #16     _SyncStreamControllerDispatch._sendDone (dart:async/stream_controller.dart:792:19)
      #17     _StreamController._closeUnchecked (dart:async/stream_controller.dart:647:7)
      #18     _StreamController.close (dart:async/stream_controller.dart:640:5)
      #19     new _WebSocketImpl._fromSocket.<anonymous closure> (dart:_http/websocket_impl.dart:1171:19)
      #20     _rootRun (dart:async/zone.dart:1391:47)
      #21     _CustomZone.run (dart:async/zone.dart:1301:19)
      #22     _CustomZone.runGuarded (dart:async/zone.dart:1209:7)
      #23     _BufferingStreamSubscription._sendDone.sendDone (dart:async/stream_impl.dart:392:13)
      #24     _BufferingStreamSubscription._sendDone (dart:async/stream_impl.dart:402:7)
      #25     _BufferingStreamSubscription._close (dart:async/stream_impl.dart:291:7)
      #26     _SinkTransformerStreamSubscription._close (dart:async/stream_transformers.dart:87:11)
      #27     _EventSinkWrapper.close (dart:async/stream_transformers.dart:21:11)
      #28     _WebSocketProtocolTransformer.close (dart:_http/websocket_impl.dart:118:17)
      #29     _SinkTransformerStreamSubscription._handleDone (dart:async/stream_transformers.dart:132:24)
      #30     _rootRun (dart:async/zone.dart:1391:47)
      #31     _CustomZone.run (dart:async/zone.dart:1301:19)
      #32     _CustomZone.runGuarded (dart:async/zone.dart:1209:7)
      #33     _BufferingStreamSubscription._sendDone.sendDone (dart:async/stream_impl.dart:392:13)
      #34     _BufferingStreamSubscription._sendDone (dart:async/stream_impl.dart:402:7)
      #35     _BufferingStreamSubscription._close (dart:async/stream_impl.dart:291:7)
      #36     _SyncStreamControllerDispatch._sendDone (dart:async/stream_controller.dart:792:19)
      #37     _StreamController._closeUnchecked (dart:async/stream_controller.dart:647:7)
      #38     _StreamController.close (dart:async/stream_controller.dart:640:5)
      #39     _Socket._onData (dart:io-patch/socket_patch.dart:2454:21)
      #40     _rootRunUnary (dart:async/zone.dart:1407:47)
      #41     _CustomZone.runUnary (dart:async/zone.dart:1308:19)
      #42     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1217:7)
      #43     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:339:11)
      #44     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
      #45     _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
      #46     _StreamController._add (dart:async/stream_controller.dart:658:7)
      #47     _StreamController.add (dart:async/stream_controller.dart:606:5)
      #48     _RawSecureSocket._closeHandler (dart:io/secure_socket.dart:899:21)
      #49     _RawSecureSocket._tryFilter (dart:io/secure_socket.dart:1029:11)
      <asynchronous suspension>

@lohanidamodar
Copy link
Member

@Andree98 can you share code to reproduce this error

@Andree98
Copy link

Andree98 commented Jan 2, 2024

@lohanidamodar I'm able to reproduce the stacktrace with this code

@override
void initState() {
  super.initState();

  final realtime = Realtime(clientInstance);

  final subscription1 = realtime.subscribe([channel1]);
  final subscription2 = realtime.subscribe([channel2]);

  subscription1.stream.listen(print);
  subscription2.stream.listen(print);
}

Run the app and wait for the subscription to be killed. For me this takes 2-3 minutes using Cloudflare proxy. when the subscriptions are killed the stacktrace will appear in the console

@SafakB
Copy link

SafakB commented Apr 12, 2024

@lohanidamodar Same issue with me, is the work in progress? Thanks

@lohanidamodar
Copy link
Member

Latest release should resolve this issue.

@KiloNovemberDelta
Copy link

Latest release should resolve this issue.

Hello and thank you for your help!
Do you mean 12.0.3 ? Or next release ?
Because I have the same issue on 12.0.3 :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests