Skip to content

Infinite Realtime Re-Subscribes after keeping the app open over night on macOS #742

Open
@EduardMe

Description

@EduardMe

Bug report

  • I confirm this is a bug with Supabase, not with my own application.
  • I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

The Realtime library is re-subscribing infinitely, locking up the app. The subscribe function calls itself again when it runs into a try-catch error.

To Reproduce

Running my app with Supabase integration, logged in and connected to the realtime notifications over night on my Mac, it becomes occasionally unresponsive with infinite calls to the subscribe() func in the realtime library. The Mac is in sleep state and probably doesn't maintain a continuous stable internet connection.

Expected behavior

It should give up re-subscribing after an error after a few retries to prevent an infinite loop.

System information

  • OS: macOS
  • Version of supabase: 2.29.3

See some logging I could extract from XCode:
inifnite-resubscribe.txt

Debugging

XCode was still open and running luckily when it happened, so I could track it back to the original call. Find above also the extracted stack trace.

In the function from the RealtimeChannelV2 file, I can see it calls subscribe() and in the try/catch block it calls subscribe() again infinitely if the subscribe call times out. Ideally, it gives up or at least checks if the device is in sleep mode or has no connection or similar.

  public func subscribe() async {
    if socket.status != .connected {
      if socket.options.connectOnSubscribe != true {
        reportIssue(
          "You can't subscribe to a channel while the realtime client is not connected. Did you forget to call `realtime.connect()`?"
        )
        return
      }
      await socket.connect()
    }

    status = .subscribing
    logger?.debug("Subscribing to channel \(topic)")

    let joinConfig = RealtimeJoinConfig(
      broadcast: config.broadcast,
      presence: config.presence,
      postgresChanges: mutableState.clientChanges,
      isPrivate: config.isPrivate
    )

    let payload = RealtimeJoinPayload(
      config: joinConfig,
      accessToken: await socket._getAccessToken(),
      version: socket.options.headers[.xClientInfo]
    )

    let joinRef = socket.makeRef()
    mutableState.joinRef = joinRef

    logger?.debug("Subscribing to channel with body: \(joinConfig)")

    await push(
      ChannelEvent.join,
      ref: joinRef,
      payload: try! JSONObject(payload)
    )

    do {
      try await withTimeout(interval: socket.options.timeoutInterval) { [self] in
        _ = await statusChange.first { @Sendable in $0 == .subscribed }
      }
    } catch {
      if error is TimeoutError {
        logger?.debug("Subscribe timed out.")
        await subscribe() // <----- Called over and over again as the connection is timing out repeatedly in sleep mode 
      } else {
        logger?.error("Subscribe failed: \(error)")
      }
    }
  }

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingrealtimeWork related to realtime packageswift

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions