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

Supabase Realtime stream cancel and initialize again #585

Closed
iampopal opened this issue Aug 10, 2023 · 6 comments
Closed

Supabase Realtime stream cancel and initialize again #585

iampopal opened this issue Aug 10, 2023 · 6 comments
Labels
bug Something isn't working realtime This issue or pull request is related to realtime

Comments

@iampopal
Copy link

iampopal commented Aug 10, 2023

Describe the bug

We are using Supabase realtime for a chat app, and we are facing an unusual behavior with stream and channels

1) We have a global cubit that listens to room status name RoomStatusCubit

This RoomStatusCubit is initialized by listening to the room_status table:

initStream() {
  var realstream = from('room_status')
      .stream(primaryKey: ['id'])
      .eq('to_uid', supabase.uid)
      .order('at');
  var subscription = realStream!.listen(
    (event) {
      log('realtime 0 listen event: $event');
      emit(
        state.copyWith(
          rooms: RoomStatus.listFrom(event),
          status: RealtimeStatus.result,
        ),
      );
    },
    onError: (e, s) {
      log('realtime 1 error: $e \ns:$s');
      if (e.toString() == '' || e.toString() == '{}') return;
      emit(state.copyWith(status: RealtimeStatus.error, error: e));
    },
  );
}

The above cubit has worked well for a while but has an issue when 


  1. the internet disconnects and reconnects 

  2. when for a long time there is no internet
    
3) when an error happens



    
To solve our above issue we have decided to close current channel and reinitalize stream 



Future cancelStream() async {
    try {
      await subscription?.cancel();
      subscription = null;
    } catch (e, s) {
      subscription = null;
      loges(e, s, type: 'realtime cancelStream');
    }
  }

  List<RealtimeChannel> get roomStatusChannels => supabase
      .getChannels()
      .where((e) => e.topic.contains('room_status'))
      .toList();

  Future cancelChannel() async {
    for (RealtimeChannel c in roomStatusChannels) {
      log('realtime cancel topic ${c.topic}');
      await supabase.removeChannel(c);
    }

    await cancelStream();
  }




The issue is when we call cancelChannel() and then initStream() the stream is not working anyway. 

currently, we need to restart our app to solve this issue and we need a better solution for restarting superbase realtime channel to work correctly so users do not close and open their app.

To Reproduce
Steps to reproduce the behavior:

  1. Create an app with realtime stream in a cubit
  2. Try to cancelChannel() and initStream()

Expected behavior
Allow us to cancel a realtime stream and init stream again without any error and stream shall work like restarting an app

Version (please complete the following information):
On Linux/macOS
Please run dart pub deps | grep -E "supabase|gotrue|postgrest|storage_client|realtime_client|functions_client" in your project directory and paste the output here.
│ └── supabase 1.10.0
│ ├── functions_client 1.3.2
│ ├── gotrue 1.11.2
│ ├── postgrest 1.5.0
│ ├── realtime_client 1.1.3
│ ├── storage_client 1.5.1
├── supabase_flutter 1.10.12
│ ├── supabase...

Additional context
We sometime also see heartbeat timeout issue and not understand how this is related
and sometime see Bad state: Cannot add event after closing error event or cubit is not closed and working correctly

@iampopal iampopal added the bug Something isn't working label Aug 10, 2023
@iampopal
Copy link
Author

iampopal commented Aug 10, 2023

Error 1: We are also getting an empty error while listening to the stream

in the following error-> there is no error
and stock-> is the stocktrace of error.

[log] error->  
stock->:#0      SupabaseStreamBuilder._addException
package:supabase/src/supabase_stream_builder.dart:442
#1      SupabaseStreamBuilder._getStreamData.<anonymous closure>
package:supabase/src/supabase_stream_builder.dart:348
#2      RealtimeChannel.subscribe.<anonymous closure>
package:realtime_client/src/realtime_channel.dart:202
#3      RealtimeChannel.onError.<anonymous closure>
package:realtime_client/src/realtime_channel.dart:331
#4      RealtimeChannel.trigger
package:realtime_client/src/realtime_channel.dart:569
#5      RealtimeClient._triggerChanError
package:realtime_client/src/realtime_client.dart:408
#6      RealtimeClient._onConnClose
package:realtime_client/src/realtime_client.dart:389
#7      RealtimeClient.connect.<anonymous closure>
package:realtime_client/src/realtime_client.dart:147
#8      _RootZone.runGuarded (dart:async/zone.dart:1581:10)
#9      _BufferingStreamSubscription._sendDone.sendDone (dart:async/stream_impl.dart:392:13)

@iampopal
Copy link
Author

iampopal commented Aug 10, 2023

Error 2: we are getting this error after a long time of our app is open:

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Bad state: Cannot add event after closing
#0      _StreamController.add (dart:async/stream_controller.dart:595:24)
#1      _CompleterSink.add
package:web_socket_channel/src/sink_completer.dart:90
#2      RealtimeClient.push.callback.<anonymous closure>
package:realtime_client/src/realtime_client.dart:267
#3      new RealtimeClient.<anonymous closure>
package:realtime_client/src/realtime_client.dart:107
#4      RealtimeClient.push.callback
package:realtime_client/src/realtime_client.dart:267
#5      RealtimeClient.push
package:realtime_client/src/realtime_client.dart:284
#6      Push.send
package:realtime_client/src/push.dart:61
#7      Push.resend
package:realtime_client/src/push.dart:52
#8      RealtimeChannel.rejoin
package:realtime_client/src/realtime_channel.dart:510
#9      RealtimeChannel.rejoinUntilConnected
package:realtime_client/src/realtime_channel.dart:181
#10     new RealtimeChannel.<anonymous closure>
package:realtime_client/src/realtime_channel.dart:134
#11     RetryTimer.scheduleTimeout.<anonymous closure>
package:realtime_client/src/retry_timer.dart:46
#12     Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
#13     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
#14     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
#15     _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:192:26)

@maxfornacon
Copy link

Your error 2 seems to be similar to the issue I descibed in #579. Could be related.

@iampopal
Copy link
Author

iampopal commented Aug 12, 2023

Your error 2 seems to be similar to the issue I descibed in #579. Could be related.

Yea, looking like #579 is related to this, and we need to cancel the stream and reinitialize the feature so in future if anything else happens in future will be easily solvable.

@iampopal
Copy link
Author

How's the progress of this going? we need to be able to close and re-initialize streams because the internet may come and go.

@bdlukaa bdlukaa added the realtime This issue or pull request is related to realtime label Jul 22, 2024
@Vinzent03
Copy link
Collaborator

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working realtime This issue or pull request is related to realtime
Projects
None yet
Development

No branches or pull requests

4 participants