sdk-for-flutter
sdk-for-flutter copied to clipboard
🐛 Bug Report: Subscribing Multiple Times with a Single Realtime Instance Results in Null Subscription
👟 Reproduction steps
- Instantiate a Realtime instance
- Subscribe to a channel
- 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:
https://github.com/appwrite/sdk-for-flutter/blob/54f30faa4a4fab2af0fe57c172550b288c9cbb4b/lib/src/realtime_mixin.dart#L85-L86
The _closeConnection()
results in the _lastUrl
being set to null
:
https://github.com/appwrite/sdk-for-flutter/blob/54f30faa4a4fab2af0fe57c172550b288c9cbb4b/lib/src/realtime_mixin.dart#L27
and the _channels.clear()
prevents future events from being dispatched properly:
https://github.com/appwrite/sdk-for-flutter/blob/54f30faa4a4fab2af0fe57c172550b288c9cbb4b/lib/src/realtime_mixin.dart#L71-L75
🎲 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?
- [X] I checked and didn't find similar issue
🏢 Have you read the Code of Conduct?
- [X] I have read the Code of Conduct
For now, the best thing to do is to use a separate Realtime instance for each subscription.
@stnguyen90 what is the behavior with other SDKs?
@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.
Same issue with me
Same here. Is there any milestone, when this will be fixed?
This needs addressing, really handicaps one of the most useful features.
Same here, what is the status of this issue?
same here. Thank you for the work.
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
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.
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.
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>
@Andree98 can you share code to reproduce this error
@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
@lohanidamodar Same issue with me, is the work in progress? Thanks
Latest release should resolve this issue.
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 :(