apollo-ios icon indicating copy to clipboard operation
apollo-ios copied to clipboard

Subscription not working after 30 minutes

Open siliconprime-manhnguyen opened this issue 3 years ago • 14 comments

Bug report

  • Subscribe to subscriptions.
  • Receiving data from subscriptions (working).
  • Still uses the app about 30 . In 30 minutes BE doesn't send anything. 31st minute BE sends data to subscriptions . The app doesn't receive anything
  • I checked apollo client webSocketTransport isConnected() = true and in list subscriptions exist data and don't have an error from apollo

The function init Apollo client

    func initApollo(){
        self.apoloStore = ApolloStore()
        let url = DeploymentMode.currentMode() == .dev ? URL(string: “dev”)! : URL(string: “prod”)!
      
        var request = URLRequest(url: url)
        webSocketTransport = WebSocketTransport(
            websocket: DefaultWebSocket(request: request),
            reconnect: true
        )
        webSocketTransport.delegate = self
        webSocketTransport.initServer()
        let provider = NetworkInterceptorProvider(client: URLSessionClient(), shouldInvalidateClientOnDeinit: false, store: apoloStore)
        
        let normalTransport = RequestChainNetworkTransport(interceptorProvider: provider,
                                                             endpointURL: url)

        let splitNetworkTransport = SplitNetworkTransport(
          uploadingNetworkTransport: normalTransport,
          webSocketNetworkTransport: webSocketTransport
        )
        self.apolloClient = ApolloClient(networkTransport: splitNetworkTransport, store: apoloStore)
    }

Subscribe to subscriptions

  func subscriptionApollo(){
       subscription = ApolloManager.shared.apolloClient
            .subscribe(subscription: NameSubscription()) { [weak self] (result) in
                guard let self = self else { return }
                switch result {
                case .success(let value):
                    LogManager.shared.log(logStr: "GRAPHQL - subscription - success ")
                    break
                case .failure(let value):
                     LogManager.shared.log(logStr: "GRAPHQL - subscription - failure ")
                    break
                }
            }
    }

Versions

Please fill in the versions you're currently using:

  • apollo-ios SDK version: 0.45.0
  • Xcode version: Version 12.4
  • Swift version: 5.0

siliconprime-manhnguyen avatar Jul 21 '21 12:07 siliconprime-manhnguyen

Thanks for the bug report! I'm not sure what would be causing this. @designatednerd any ideas from your experience?

AnthonyMDev avatar Jul 21 '21 18:07 AnthonyMDev

Thanks @siliconprime-manhnguyen, I've got a couple questions:

  • does the app stay in the foreground all the time?
  • is it 30 minutes from init subscription or 30 minutes from last received data?

calvincestari avatar Jul 21 '21 19:07 calvincestari

@calvincestari

  • Yes , The app stay in the foreground all the time
  • 30 minutes from last received data

siliconprime-manhnguyen avatar Jul 22 '21 01:07 siliconprime-manhnguyen

Weird! I haven't seen this at all.

  • Is this new behavior in 0.45.0 or was this also happening before?
  • You mentioned the app is in the foreground - can you confirm that either the screen is disabled from locking or that the app is in use for those 30 minutes? Basically want to make sure the device didn't lock.
  • Is it only after 30 minutes specifically, or is that just the amount of time you were testing for?
  • Is there any other data going over the web socket from the app, like pings or anything like that?
  • Does the server think the websocket connection is still open?
  • Are you able to tell if anything comes in over the wire to the app? You should be able to throw in a breakpoint at either WebSocketTransport.didReceive(event:) and/or WebSocket.didReceive(event:) and see if either of those get hit when stuff comes in over the wire.

In theory if the server dropped the connection there should be an error, but stranger things have happened.

designatednerd avatar Jul 22 '21 04:07 designatednerd

@designatednerd

  • Is this new behavior in 0.45.0 or was this also happening before? I don't know exactly the version was this happened but the two last versions were (0.45.0 and 0.44.0) happening
  • You mentioned the app is in the foreground - can you confirm that either the screen is disabled from locking or that the app is in use for those 30 minutes? Basically want to make sure the device didn't lock. Yes i'm sure that the device didn't lock because the user still can see another user live stream and playing game
  • Is there any other data going over the web socket from the app, like pings or anything like that? Yes we have a ping pong 30 seconds at a time when the issues happing ping_pong still working Below is function send and receive ping pong
func sendPing() {
       LogManager.shared.log(logStr: "SOCKET - send ping", isSaveToFile: AppDelegate.shared.isLogToFile)
       self.socket?.write(ping: Data(), completion: nil)
}

func websocketDidReceivePong(socket: WebSocketClient, data: Data?) {
       LogManager.shared.log(logStr: "SOCKET - receive pong", isSaveToFile: AppDelegate.shared.isLogToFile)
       self.lastPongTime = Date()
}
  • Does the server think the websocket connection is still open? Yes, websocket connection is still opening. because Android and web still working normally

  • Are you able to tell if anything comes in over the wire to the app? Sorry I still find it but I don't know the reason

  • You should be able to throw in a breakpoint at either WebSocketTransport.didReceive(event:) and/or WebSocket.didReceive(event:) and see if either of those get hit when stuff comes in over the wire. Thank you for your suggestions I will check about that

siliconprime-manhnguyen avatar Jul 22 '21 07:07 siliconprime-manhnguyen

Thanks for all the info! I'm wondering what the best method to investigate this is. I want to figure out if this is an issue with Apollo, or with Starscream (the library we use for the websocket connection under the hood).

AnthonyMDev avatar Jul 22 '21 17:07 AnthonyMDev

This issue could be related: https://github.com/daltoniam/Starscream/issues/649 This may be an Apple issue, and the workaround is to have the websocket send a ping periodically to prevent the stream from going stale.

@designatednerd Do you think that is something we should bake into Apollo?

AnthonyMDev avatar Jul 22 '21 17:07 AnthonyMDev

Yeah that certainly sounds like it could be it.

I can see arguments both ways in terms of baking it into Apollo or not: Theoretically the websocket is an implementation detail of subscriptions, so we should build in some kind of auto-ping mechanism to disguise that detail (pro), but also not every websocket server handles pings exactly the same way and it's not entirely clear how often we'd need to do this, so it might be something better for each dev to configure what they actually need rather than us setting it up by default (con).

If we do it, maybe a default setup where it pings every N seconds, and passing 0 or less just turns off the ping? Or an enum of (none, every(seconds: UInt)`)?

designatednerd avatar Jul 22 '21 18:07 designatednerd

@AnthonyMDev @designatednerd Thank you so much for your investigate Do you plan to release next time to resolve the problem? We really really looking forward to that because all ios users are affected This is very important for us

siliconprime-manhnguyen avatar Jul 23 '21 01:07 siliconprime-manhnguyen

Hi, @designatednerd @AnthonyMDev Could you please let me know if there is any news? Can you give me advice on a workaround solution to resolve the problem?

siliconprime-manhnguyen avatar Jul 27 '21 03:07 siliconprime-manhnguyen

I'm going to keep this open to work on it in the future, but for now, I think you should just set up a timer that periodically sends a ping. You can have it call the WebSocketTransport.ping() function with some dummy data that your server can ignore to keep the connection open.

AnthonyMDev avatar Jul 27 '21 17:07 AnthonyMDev

Hi, I'm also facing very similar issue.

So in my case web socket(subscription) stop receiving updates from server after 10-15 minutes but i can see ping pong event in Charles proxy.

  • On app launch fetch 10 items using api call and subscribe for each item individually.
  • Every 30 seconds I'm refetching 10 items using api call and canceling previous subscription and making new subscription
  • App is always in foreground without screen lock.
  • I can see app canceling(type:complete) old subscription and making new subscription(type: subscribe) with ping/pong around every 12 seconds
  • Initially(first 10-15 minutes) i can see app receiving updates
  • In order to cross check I also open parallel subscription using Postman and after 10-15 minutes i can see events in post man but not in app
  • My Apollo library version is 1.9.0
class MySubscriptionClient {
    private let apolloClient: ApolloClient?
    
    init(url: URL?) {
        var component = URLComponents(string: url?.absoluteString ?? "")
        component?.scheme = "wss"
        if let url = component?.url {
            /// A common store to use for `httpTransport` and `webSocketTransport`.
            let store = ApolloStore()
            
            /// A web socket transport to use for subscriptions
            let webSocketTransport: WebSocketTransport = {
                let webSocketClient = WebSocket(url: url, protocol: .graphql_transport_ws)
                webSocketClient.enableSOCKSProxy = true
                return WebSocketTransport(
                    websocket: webSocketClient
                )
            }()
            self.apolloClient = ApolloClient(networkTransport: webSocketTransport, store: store)
        } else {
            self.apolloClient = nil
            log("SubscriptionClient: Unable to initialise ApolloClient!", type: .error)
        }
    }
}

satishVekariya avatar Mar 20 '24 21:03 satishVekariya

I'm sorry you're experiencing this issue. I'm not sure what could be causing this. 🤔

Cancelling and restarting your subscriptions every 30 seconds theoretically should work, but it might be causing some sort of race condition or bug we aren't aware of?

If you are pinging the web socket and getting success responses every 12 seconds, it really should continue to work. At the point when the subscription stops receiving updates, are the ping/pong events still continuing to work correctly?

AnthonyMDev avatar Mar 20 '24 22:03 AnthonyMDev

Hi @AnthonyMDev, Yes i can see ping/pong events works correctly(in Charles) after its stops receiving updates!

satishVekariya avatar Mar 21 '24 08:03 satishVekariya