supabase / supabase-flutter

Flutter integration for Supabase. This package makes it simple for developers to build secure and scalable products.
https://supabase.com/
MIT License
698 stars 163 forks source link

Exception: Realtime was unable to connect to the project database #982

Open maxfornacon opened 1 month ago

maxfornacon commented 1 month ago

Describe the bug I initialised a realtime channel and after a while of inactivity I get the following Exception. The channel doesn't receive data after that and does not recover on its own.

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Exception: "Realtime was unable to connect to the project database"
#0      SupabaseStreamBuilder._addException (package:supabase/src/supabase_stream_builder.dart:293:67)
#1      SupabaseStreamBuilder._getStreamData.<anonymous closure> (package:supabase/src/supabase_stream_builder.dart:199:9)
#2      RealtimeChannel.subscribe.<anonymous closure> (package:realtime_client/src/realtime_channel.dart:207:19)
#3      Push._matchReceive.<anonymous closure> (package:realtime_client/src/push.dart:133:17)
#4      Iterable.forEach (dart:core/iterable.dart:347:35)
#5      Push._matchReceive (package:realtime_client/src/push.dart:132:48)
#6      Push.startTimeout.<anonymous closure> (package:realtime_client/src/push.dart:96:7)
#7      RealtimeChannel.trigger (package:realtime_client/src/realtime_channel.dart:694:22)
#8      new RealtimeChannel.<anonymous closure> (package:realtime_client/src/realtime_channel.dart:93:7)
#9      RealtimeChannel.trigger (package:realtime_client/src/realtime_channel.dart:694:22)
#10     RealtimeClient.onConnMessage.<anonymous closure>.<anonymous closure> (package:realtime_client/src/realtime_client.dart:319:41)
#11     Iterable.forEach (dart:core/iterable.dart:347:35)
#12     RealtimeClient.onConnMessage.<anonymous closure> (package:realtime_client/src/realtime_client.dart:319:12)
#13     new RealtimeClient.<anonymous closure> (package:realtime_client/src/realtime_client.dart:135:21)
#14     RealtimeClient.onConnMessage (package:realtime_client/src/realtime_client.dart:302:11)
#15     RealtimeClient.connect.<anonymous closure> (package:realtime_client/src/realtime_client.dart:165:22)
#16     _RootZone.runUnaryGuarded (dart:async/zone.dart:1594:10)
#17     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
#18     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
#19     _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:123:11)
#20     _HandleErrorStream._handleData (dart:async/stream_pipe.dart:253:10)
#21     _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
#22     _RootZone.runUnaryGuarded (dart:async/zone.dart:1594:10)
#23     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
#24     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
#25     _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
#26     _StreamController._add (dart:async/stream_controller.dart:658:7)
#27     _RootZone.runUnaryGuarded (dart:async/zone.dart:1594:10)
#28     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
#29     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
#30     _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
#31     _StreamController._add (dart:async/stream_controller.dart:658:7)
#32     _StreamController.add (dart:async/stream_controller.dart:606:5)
#33     new _WebSocketImpl._fromSocket.<anonymous closure> (dart:_http/websocket_impl.dart:1144:21)
#34     _RootZone.runUnaryGuarded (dart:async/zone.dart:1594:10)
#35     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
#36     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
#37     _SinkTransformerStreamSubscription._add (dart:async/stream_transformers.dart:63:11)
#38     _EventSinkWrapper.add (dart:async/stream_transformers.dart:13:11)
#39     _WebSocketProtocolTransformer._messageFrameEnd (dart:_http/websocket_impl.dart:332:23)
#40     _WebSocketProtocolTransformer.add (dart:_http/websocket_impl.dart:226:46)
#41     _SinkTransformerStreamSubscription._handleData (dart:async/stream_transformers.dart:111:24)
#42     _RootZone.runUnaryGuarded (dart:async/zone.dart:1594:10)
#43     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
#44     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297: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     _Socket._onData (dart:io-patch/socket_patch.dart:2449:41)
#49     _RootZone.runUnaryGuarded (dart:async/zone.dart:1594:10)
#50     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
#51     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
#52     _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
#53     _StreamController._add (dart:async/stream_controller.dart:658:7)
#54     _StreamController.add (dart:async/stream_controller.dart:606:5)
#55     _RawSecureSocket._sendReadEvent (dart:io/secure_socket.dart:1116:19)
#56     Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
#57     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
#58     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
#59     _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)

To Reproduce Steps to reproduce the behavior: I'm testing on Flutter for macOS.

  1. Initialise Stream
    var channel = Supabase.instance.client
        .channel('notifications')
        .onPostgresChanges(
          event: PostgresChangeEvent.all,
          schema: 'xxx',
          table: 'notifications',
          callback: (payload) {
            print('Change received: ${payload.toString()}');
            if (payload.errors != null && payload.errors.isNotEmpty) {
              payload.errors.forEach((element) {
                print('Error: ${element.message}');
              });
            }
          },
        )
        .subscribe();
  2. Leave Computer unattended for a while
  3. See error

Expected behavior I expect the channel to reconnect and to get notified about it by an onReconnect event or something like that.

Version (please complete the following information): supabase_test 1.0.0+1 ├── supabase_flutter 2.5.8 │ ├── supabase 2.2.4 │ │ ├── functions_client 2.2.0 │ │ ├── gotrue 2.8.3 │ │ ├── postgrest 2.1.2 │ │ ├── realtime_client 2.2.0 │ │ ├── storage_client 2.0.2

maxfornacon commented 1 month ago

Sometimes there is also this exception:

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Exception: "Invalid JWT Token"
#0      SupabaseStreamBuilder._addException (package:supabase/src/supabase_stream_builder.dart:293:67)
#1      SupabaseStreamBuilder._getStreamData.<anonymous closure> (package:supabase/src/supabase_stream_builder.dart:199:9)
#2      RealtimeChannel.subscribe.<anonymous closure> (package:realtime_client/src/realtime_channel.dart:207:19)
#3      Push._matchReceive.<anonymous closure> (package:realtime_client/src/push.dart:133:17)
#4      Iterable.forEach (dart:core/iterable.dart:347:35)
#5      Push._matchReceive (package:realtime_client/src/push.dart:132:48)
#6      Push.startTimeout.<anonymous closure> (package:realtime_client/src/push.dart:96:7)
#7      RealtimeChannel.trigger (package:realtime_client/src/realtime_channel.dart:694:22)
#8      new RealtimeChannel.<anonymous closure> (package:realtime_client/src/realtime_channel.dart:93:7)
#9      RealtimeChannel.trigger (package:realtime_client/src/realtime_channel.dart:694:22)
#10     RealtimeClient.onConnMessage.<anonymous closure>.<anonymous closure> (package:realtime_client/src/realtime_client.dart:319:41)
#11     Iterable.forEach (dart:core/iterable.dart:347:35)
#12     RealtimeClient.onConnMessage.<anonymous closure> (package:realtime_client/src/realtime_client.dart:319:12)
#13     new RealtimeClient.<anonymous closure> (package:realtime_client/src/realtime_client.dart:135:21)
#14     RealtimeClient.onConnMessage (package:realtime_client/src/realtime_client.dart:302:11)
#15     RealtimeClient.connect.<anonymous closure> (package:realtime_client/src/realtime_client.dart:165:22)
#16     _RootZone.runUnaryGuarded (dart:async/zone.dart:1594:10)
#17     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
#18     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
#19     _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:123:11)
#20     _HandleErrorStream._handleData (dart:async/stream_pipe.dart:253:10)
#21     _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
#22     _RootZone.runUnaryGuarded (dart:async/zone.dart:1594:10)
#23     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
#24     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
#25     _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
#26     _StreamController._add (dart:async/stream_controller.dart:658:7)
#27     _RootZone.runUnaryGuarded (dart:async/zone.dart:1594:10)
#28     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
#29     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
#30     _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
#31     _StreamController._add (dart:async/stream_controller.dart:658:7)
#32     _StreamController.add (dart:async/stream_controller.dart:606:5)
#33     new _WebSocketImpl._fromSocket.<anonymous closure> (dart:_http/websocket_impl.dart:1144:21)
#34     _RootZone.runUnaryGuarded (dart:async/zone.dart:1594:10)
#35     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
#36     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
#37     _SinkTransformerStreamSubscription._add (dart:async/stream_transformers.dart:63:11)
#38     _EventSinkWrapper.add (dart:async/stream_transformers.dart:13:11)
#39     _WebSocketProtocolTransformer._messageFrameEnd (dart:_http/websocket_impl.dart:332:23)
#40     _WebSocketProtocolTransformer.add (dart:_http/websocket_impl.dart:226:46)
#41     _SinkTransformerStreamSubscription._handleData (dart:async/stream_transformers.dart:111:24)
#42     _RootZone.runUnaryGuarded (dart:async/zone.dart:1594:10)
#43     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
#44     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297: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     _Socket._onData (dart:io-patch/socket_patch.dart:2449:41)
#49     _RootZone.runUnaryGuarded (dart:async/zone.dart:1594:10)
#50     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
#51     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
#52     _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
#53     _StreamController._add (dart:async/stream_controller.dart:658:7)
#54     _StreamController.add (dart:async/stream_controller.dart:606:5)
#55     _RawSecureSocket._sendReadEvent (dart:io/secure_socket.dart:1116:19)
#56     Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
#57     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
#58     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
#59     _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)

I believe that this happens when the JWT expires while the system is asleep. After the application gets into active/resumed state again I can read: **** onAuthStateChange: AuthChangeEvent.tokenRefreshed in the log. But the stream is not recovering.