supabase-flutter icon indicating copy to clipboard operation
supabase-flutter copied to clipboard

Bug: Stream behaviour on connection lost and reconnect

Open coolusaHD opened this issue 2 years ago • 14 comments

Describe the bug With the update to 1.2.3 , losing the connection doesn't trigger any error anymore. Also reconnecting to the internet doesn't change/trigger anything.

My current code (with v1.2.2)

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

class RealtimeGameService extends ChangeNotifier {
  RealtimeGameService({
    required this.client,
    required this.primaryKey,
    required this.tableName,
  }) {
    _init();
  }

  final SupabaseClient client;
  final String tableName;
  final List<String> primaryKey;

  List<Map<String, dynamic>> data = [];
  DateTime lastUpdateTime = DateTime.now();
  bool isConnected = false;
  bool isInitialLoading = true;

  StreamSubscription<List<Map<String, dynamic>>>? _streamSubscription;

  void _init() {
    _streamSubscription?.cancel(); // Cancel any existing subscription
    final liveDataStream =
        client.from(tableName).stream(primaryKey: primaryKey);

    _streamSubscription = liveDataStream.listen(
      (List<Map<String, dynamic>> newData) {
        print('works');
        print('Received data: $newData');
        _updateData(newData, true);
        if (isInitialLoading) {
          isInitialLoading = false; // Mark initial loading as complete
          notifyListeners();
        }
      },
      onError: (e) {
        print('Error during realtime subscription: $e');
        _updateData(data, false);
        if (isInitialLoading) {
          isInitialLoading = false; // Mark initial loading as complete
          notifyListeners();
        }
      },
      onDone: () {
        print('Realtime subscription done');
      },
    );
  }

  void _updateData(List<Map<String, dynamic>> newData, bool newIsConnected) {
    data = newData;
    lastUpdateTime = newIsConnected ? DateTime.now() : lastUpdateTime;
    isConnected = newIsConnected;
    notifyListeners();
  }

  void reload() {
    _init();
    isInitialLoading = true;
    notifyListeners();
  }

  @override
  void dispose() {
    _streamSubscription?.cancel();
    super.dispose();
  }
}

Expected behavior

  1. At least one single error should be thrown that the websocket lost connection
  2. It would be nice if the websocket reconnects it triggers the onData again

Version (please complete the following information): ????????? realtime_client 1.2.2 ????????? supabase_flutter 1.10.18 ??? ????????? supabase 1.11.5 ??? ??? ????????? functions_client 1.3.2 ??? ??? ????????? gotrue 1.12.4 ??? ??? ????????? postgrest 1.5.1 ??? ??? ????????? realtime_client... ??? ??? ????????? storage_client 1.5.3

coolusaHD avatar Oct 18 '23 12:10 coolusaHD

Thanks for opening this @coolusaHD

I'm assuming the reason why you want to receive error within onError when listening to stream is to restart the stream when the connection is lost, correct? We are working on making the .stream() method more reliable so that it will self-reconnect if the realtime connection gets lost for any reason. If this is implemented, would you say there is no need to have an API to detect if the stream lost its connection?

dshukertjr avatar Oct 27 '23 04:10 dshukertjr

@dshukertjr In my implementation I use the onError for notifiy the user that he no longer recieves the latest data. To reconnect the user itself have to press a button to retry/ reinit the stream subscription.

So to answer your question: No I dont use it to automatically reconnect to the stream.

Therefore it would be nice if the stream would automatically reconnect and recall the onData callback but it would be also nice (and essential for me) that at least the onError gets triggered once when the stream lost the connection.

Thanks for asking🙌

coolusaHD avatar Oct 27 '23 07:10 coolusaHD

@dshukertjr Any ideas when the work on making the ".stream() method more reliable" is going to be finished? Or available for a first testing?

bigbenyayi avatar Oct 31 '23 14:10 bigbenyayi

Any updates on this ? ✌️ @dshukertjr

coolusaHD avatar Dec 19 '23 13:12 coolusaHD

Thanks for opening this @coolusaHD

I'm assuming the reason why you want to receive error within onError when listening to stream is to restart the stream when the connection is lost, correct? We are working on making the .stream() method more reliable so that it will self-reconnect if the realtime connection gets lost for any reason. If this is implemented, would you say there is no need to have an API to detect if the stream lost its connection?

Is there an ETA on this? Stream is so buggy right now it is really difficult to trust it.

elliottetzkorn avatar Feb 02 '24 04:02 elliottetzkorn

@dshukertjr I had some freetime and testet a bit. The change of the _onConnError function also prevents that the onError function of the stream gets the error.

But thats not the only problem. If the connection fails the heartbeat should also fail and close the stream after 2 missed heartbeats. But that doesn't trigger anything.

So from my perspective I see why the flooding of errors should be prevented but without any error how can I know if my stream is still connected to the source?

I really like to update to the latest version but my app cant live without that 😅

Is there any change to make the error flooding optional or even fix it that it returns at least one error?

Thanks in advance. ✌️

coolusaHD avatar Apr 16 '24 14:04 coolusaHD

I would also like to vote that at least an error message is displayed when the streams stop receiving data.

Supabase and the supabase_flutter package are such great products, but with faulty realtime support in certain cases, the package is simply not ready for production applications imho. This should at least be openly communicated to the customers. If someone knows a reliable workaround for the stream issues, I would love to know about it. I couldn't find one myself over the last months and that's holding us back.

Any official statement would be highly appreciated. Otherwise, I love everything about Supabase and would recommend it anytime.

maxfornacon avatar Apr 29 '24 13:04 maxfornacon

Hope quick solve this issue. I also lost connect and do not receive error from stream.onError callback. It it difficult to fix it for the app developer.

fan123199 avatar May 10 '24 04:05 fan123199

I just built a ton on top of realtime SQL updates, assuming it would be easy to add in some reconnect logic once I got around to it... and this... seems like a pretty fundamental thing to prioritize

Has anyone figured out any workarounds?

themightychris avatar Aug 26 '24 21:08 themightychris

Hi @dshukertjr, is there any update on the fix?

My issue is the connection gets lost when the app is in the background for a while. When the app becomes active again, it doesn't seem to automatically reconnect and thus only display the stale data which were received before the connection was lost.

I tried to work around this issue by listening to the app lifecycle change to manually reconnect. However, I am concerned of this approach because there's no way to manually close the stream right now (or at least I couldn't find a way to do it). This means that there could be multiple stream open simultaneously which may lead to memory leak.

Given that most of apps inherently will go to background for a long period of time, this seems to be a serious issue because app will only display stale data. In my case, I am sending a push notification whenever there's new chat message but when clicking on it to land on the chatroom, the latest message often is not present.

yunpaik avatar Aug 29 '24 08:08 yunpaik

Will #1019 address this?

themightychris avatar Sep 08 '24 13:09 themightychris

Will #1019 address this?

It looks like better error handling. If this will trigger the onError callback function in the stream.listen() functionwould be nice and propably fix the error

coolusaHD avatar Sep 08 '24 17:09 coolusaHD

With modified pubspec.yaml

  realtime_client: ^2.2.1
  supabase_flutter: ^2.6.0
  supabase: ^2.3.0

dependency_overrides: 
  supabase_flutter: 
    git:
      url: https://github.com/supabase/supabase-flutter/
      ref: fix/realtime
      path: ./packages/supabase_flutter
  realtime_client:
    git:
      url: https://github.com/supabase/supabase-flutter
      ref: fix/realtime
      path: ./packages/realtime_client
  supabase:
    git:
      url: https://github.com/supabase/supabase-flutter
      ref: fix/realtime
      path: ./packages/supabase

After I dissconnected the internet on the device the stream takes about 40s to check and then throws an error so my app can show that it is no longer connected to the internet. After reconnecting it instantly works again like before.

See #1019

coolusaHD avatar Sep 13 '24 14:09 coolusaHD

@Vinzent03 @dshukertjr I'm gonna close this isse when #1019 gets merged ✌️ 🚀

coolusaHD avatar Sep 13 '24 14:09 coolusaHD

With #1019 being merged now, these issues should be solved now. You can try them by upgrading supabase_flutter to 2.7.0. If you still experience any issues, please create a new issue.

Vinzent03 avatar Oct 03 '24 10:10 Vinzent03