davidstump / SwiftPhoenixClient

Connect your Phoenix and iOS applications through WebSockets!
MIT License
507 stars 147 forks source link

Question channel rejoin after socket reconnect #181

Closed ruslandoga closed 3 years ago

ruslandoga commented 3 years ago

👋

I have two questions:

  1. Do socket.channels get automatically rejoined if socket reconnects? I'm running socket.disconnect() when app goes to background and socket.connect() when it goes back into foreground (similar to https://github.com/davidstump/SwiftPhoenixClient/issues/104#issuecomment-400039762, I guess) and it doesn't seem to be the case. I'm not seeing JOINED logs on the server.
  2. How can we get the response of rejoin, would join push callback be called?
channel.join().receive("ok") { message in
  // does this get re-executed on socket reconnect?
}

I've tried both 1.3.0 and 2.x branch as well, channels don't seem to be rejoined in either. Maybe they are not supposed to? I can create a repo with my reconnection logic if it'd help.

And thank you for maintaining the library!

ruslandoga commented 3 years ago

re 1. it doesn't seem like channels are rejoined on connect after clean disconnect. But then I wonder why socket.channels are not cleaned up on socket.disconnect()? This leads to all channel.push being discarded by backend with ignoring unmatched topic warning.

I suggest rejoining socket.channels after reconnect and re-executing joinPush callbacks if there are any. Basically adding something like

channels.forEach { channel in
  channel.rejoin()
  // + reset timer
  // + reexecute joinPush callbacks
}

at the end of Socket.connect.

I can open a PR if this suggestion makes sense.

dsrees commented 3 years ago

Thanks for the issue! I believe that the client is working as designed. A channel can only .join() once.

// Chanel.swift
public func join(timeout: TimeInterval? = nil) -> Push {
    guard !joinedOnce else {
      fatalError("tried to join multiple times. 'join' "
        + "can only be called a single time per channel instance")
    }
    ...
 }

After calling socket.disconnect(), the channels should be moved to the closed state and are considered finished. In order to open the Channels again after calling socket.connect() then you will have to re-create new Channels.

When a Channel closes then it should remove itself from the socket. There may be a bug where this is not happening.

ruslandoga commented 3 years ago

@dsrees ah, perfect. I guess I misused the library since I kind of relied on channels automatically rejoining if socket is connected (both after network issues and after manual disconnect -> connect).

There may be a bug where this is not happening.

I can make a repo where channels stay in the socket after it disconnects and then connects back.

And this issue seems to be resolved, so I think I'll close it.

ruslandoga commented 3 years ago

Actually, channels might be staying in socket.channels after disconnect due to my misuse. I keep references to the channels in service objects, so when the app comes back into foreground, ARC doesn't release the channels even though they are defunct now ...

I'll put socket/channels into a separate layer where no other object in memory directly references them and see if the channels still are not released on disconnect.

dsrees commented 3 years ago

Just declare your channels as optional and then set them to nil when you call socket.disconnect()