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

The connection retry doesn't stop after being disconnected. #32

Open
EternalYouth29 opened this issue Oct 2, 2024 · 7 comments
Open
Assignees
Labels
bug Something isn't working Fixed in Pre-release

Comments

@EternalYouth29
Copy link

Hi,

Thank you for your effort in building this package!

I am encountering an issue with duplicate connections.

In my code, I disconnect when the app goes inactive or moves to the background, and reconnect when it resumes. This works fine in most cases.

However, while testing the internet connection, I noticed an issue. When the internet is disabled and the reconnect is triggered, if I put the app in the background, it still tries to reconnect. After reconnecting to the internet and resuming the app, the reconnect logic (as I mentioned earlier) is triggered and connects to SSE. At the same time, the retry logic also connects to SSE, resulting in two connections (I am using EventFlux.instance.connect()), I get double data at the same time.

When I put the app back into the background, I get the following error:

I/flutter (12133): ----------------FIREBASE CRASHLYTICS---------------- I/flutter (12133): Bad state: Cannot add event after closing I/flutter (12133): #0 _StreamController.add (dart:async/stream_controller.dart:605:24) I/flutter (12133): #1 EventFlux._start.<anonymous closure>.<anonymous closure> (package:eventflux/client.dart:325:36) I/flutter (12133): #2 _RootZone.runUnaryGuarded (dart:async/zone.dart:1594:10) I/flutter (12133): #3 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:339:11) I/flutter (12133): #4 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7) I/flutter (12133): #5 _SinkTransformerStreamSubscription._add (dart:async/stream_transformers.dart:63:11) I/flutter (12133): #6 _EventSinkWrapper.add (dart:async/stream_transformers.dart:13:11) I/flutter (12133): #7 _StringAdapterSink.add (dart:convert/string_conversion.dart:228:11) I/flutter (12133): #8 _LineSplitterSink._addLines (dart:convert/line_splitter.dart:164:13) I/flutter (12133): #9 _LineSplitterSink.addSlice (dart:convert/line_splitter.dart:131:7) I/flutter (12133): #10 StringConversionSink.add (dart:convert/string_conversion.dart:39:5) I/flutter (12133): #11 _SinkTransformerStreamSubscription._handleData (dart:async/stream_transformers.dart:111:24) I/flutter (12133): #12 _RootZone.runUnaryGuarded (dart:async/zone.dart:1594:10) I/flutter (12133): ----------------------------------------------------
Could you clarify the expected behavior of the reconnect functionality? Should it stop reconnecting when EventFlux.instance.disconnect() is called? Also, how can I prevent multiple connections when using EventFlux.instance.connect()?

Thanks for your time and help!

@Imgkl
Copy link
Owner

Imgkl commented Oct 3, 2024

Hi @EternalYouth29,

Thank you for your kind words and for pointing out the issue!

Based on the logs and your explanation, it looks like the core problem is that data is being added to the stream after it has already been closed, which causes the "Bad state: Cannot add event after closing" error. This occurs because the stream isn't fully cleaned up when a disconnection or reconnection is triggered. Additionally, the reconnect logic seems to continue running in the background even after calling disconnect(), leading to multiple connections and duplicate data streams.

I'm working on a fix to:

  • Ensure the stream controller is properly closed and cleaned up before reconnecting.
  • Stop reconnection attempts after disconnect() is called, to avoid multiple active connections.

I'll let you know once the fix is ready. Thanks again for your detailed report and patience!

@Imgkl Imgkl added the bug Something isn't working label Oct 3, 2024
@Imgkl Imgkl self-assigned this Oct 3, 2024
@EternalYouth29
Copy link
Author

Hi @Imgkl ,

Thanks for the update! I appreciate your efforts in fixing the issue. Looking forward to the update!

@Imgkl
Copy link
Owner

Imgkl commented Oct 4, 2024

Hi @EternalYouth29,

I've pushed a pre-release version with these fixes. Possible to try this version and let me know, if this fixes your problem?

https://pub.dev/packages/eventflux/versions/2.2.2-dev.1

If this issue still persists, reproducible code would helpful.

@EternalYouth29
Copy link
Author

Hi @Imgkl ,

Thanks for the quick update! I tested the pre-release version, and the Bad state: Cannot add event after closing error has been resolved. However, the second issues till persists -- reconnection attempts continue even after disconnect() is called.

    EventFlux.instance.connect(
      EventFluxConnectionType.post,
      'domain.com',
      header: header,
      body: body,
      onSuccessCallback: (EventFluxResponse? data) {
        if (data?.status == EventFluxStatus.connected) {
          data?.stream?.listen((EventFluxData event) {
            DebugLogger.log("event data: ${event.data}", "SseBloc");
            // logic
          });
        }
      },
      onError: (EventFluxException error) async {
        DebugLogger.log('Error connecting to SSE: ${error.message}, ${error.statusCode}, ${error.reasonPhrase}', 'SseBloc');
      },
      autoReconnect: true,
      reconnectConfig: ReconnectConfig(
        mode: ReconnectMode.linear,
        interval: const Duration(seconds: 5),
        maxAttempts: 5,
        onReconnect: () {
          DebugLogger.log('Reconnecting to SSE', 'SseBloc');
        },
      ),
    );

The SseEvent.closeSse() basically just call EventFlux.instance.disconnect().

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.resumed:
        sseBloc.add(const SseEvent.connectSse());
        break;
      case AppLifecycleState.inactive:
        sseBloc.add(const SseEvent.closeSse());
        break;
      case AppLifecycleState.paused:
        sseBloc.add(const SseEvent.closeSse());
        break;
      case AppLifecycleState.detached:
        sseBloc.add(const SseEvent.closeSse());
        break;
      case AppLifecycleState.hidden:
        sseBloc.add(const SseEvent.closeSse());
        break;
    }
  }

With the above code setup, after the SSE is connected, try disabling the internet connection and putting the app in the background. In the debug console, you'll still see this log: [EventFlux 2024-10-05 13:12:14.980182] 🔄 Trying again in 5 seconds. Then, if you re-enable the internet connection and resume the app, multiple event.data entries are printed in the debug console.

Thanks for your time and effort!

@Imgkl
Copy link
Owner

Imgkl commented Oct 6, 2024

@EternalYouth29 Thanks for your patience and your code.

I've zeroed in on the issue which causes the reconnection logic to run even after explicit disconnect.

I've pushed a fix for this on pre-release

https://pub.dev/packages/eventflux/versions/2.2.2-dev.2

I am now clearing the reconnectLogic data on disconnect. Thus ensuring the reconnect logic is not started successfully. You might see the "🔄 Trying again in X seconds" once, depends on the last retry time, but I've tried it multiple times, Upon opening the app, only once connection is established.

Here is the code, I used to test this flow with.

https://gist.github.com/Imgkl/d6b88896118a03a315156ecf178153e7

Hope this fix solves your issue.

@EternalYouth29
Copy link
Author

Hi @Imgkl ,

I've tested your code example with my API, but I am still receiving duplicate data. Here are the steps to reproduce the issue:

  1. Click Connect to connect to the SSE.
  2. After connecting, turn on Airplane mode.
  3. Return to the app and wait for 5 seconds.
  4. Turn off Airplane mode and go back to the app.

Once reconnected, I start receiving two instances of [log] Stream Data incoming every second (the server sends data every 1 second).
https://imgur.com/htLHOex

Additionally, in step 4, if I click Connect a few times before the phone reconnects to the internet, I end up receiving multiple instances of [log] Stream Data incoming every second.

@liugaocomeon
Copy link

Hi @Imgkl When automatic reconnection is enabled, if disconnect() is called before connect() is called after an exception occurs, a problem will occur. For example, if the server closes the connection, an exception will be triggered to start reconnecting. If disconnect() is called before connect() is called during reconnection, a problem will occur. The fundamental problem is that there will be two connection requests.

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

No branches or pull requests

3 participants