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

Getting error.code == .unknown after backgrounding the app, coming back, and making request #339

Open
aheze opened this issue Jan 23, 2025 · 3 comments
Assignees

Comments

@aheze
Copy link

aheze commented Jan 23, 2025

In our app's backend event logs, we are seeing ConnectError with code .unknown quite frequently. This seems to occur when the user starts an app session (app becomes foregrounded) but then doesn't do anything for a while. Then, as soon as a gRPC request is made (checkAuthStatus) we see the error.

Here are some screenshots:

Coming back after 2 hours Coming back after 5 minutes
Image Image

The error does not tell us anything except that the code is .unknown. Is this due to the gRPC pool timing out? Is there something we can do to refresh the gRPC session?

Btw, here's the code that we have to check auth status every 30 min:

func continuouslyCheckAuthStatus() {
    let timer = Timer.scheduledTimer(withTimeInterval: 1800, repeats: true) { [weak self] _ in
        self?.performTask()
    }

    // Add the timer to the current run loop
    RunLoop.current.add(timer, forMode: .common)
}

// called every 30 minutes
func performTask() {
    checkAuthStatus()
}

We are using gRPC:

let client = ProtocolClient(
    httpClient: NIOHTTPClient(host: host, port: port, timeout: 120),
    config: ProtocolClientConfig(
        host: host,
        networkProtocol: .grpc,
        codec: ProtoCodec()
    )
)
@rebello95
Copy link
Collaborator

👋🏽 hey @aheze, thanks for flagging this. Can you share more details on what checkAuthStatus() is doing? Is it a unary request? Do you open gRPC streams or send any other requests when the user opens the app? (In other words, is the request returning .unknown the first request your app sends?) I'm also curious to know if the error's message has any info?

I think the NIO connection may be timing out / disconnecting while the app is backgrounded and your timer expires before the user foregrounds the app. Since the OS won't send the request after the app has been backgrounded for minutes, when the user foregrounds the app the OS tries to send the request but the connection is dead. Based on this code and where it's used, retrying the request should reconnect it and send the request over the new connection.

@rebello95 rebello95 self-assigned this Jan 25, 2025
@aheze
Copy link
Author

aheze commented Jan 26, 2025

Hey! checkAuthStatus pings our server and checks if the user is authenticated. It's a unary request:

let response = try await self.authFrontendClient.getAuthStatus(request: Google_Protobuf_Empty(), headers: self.headers).result.get()

We call this every 30 minutes and also in sceneDidBecomeActive. It's the first thing the app sends upon coming into the foreground.

I suspect NIO too. We may eventually move to Connect + URLSession which I feel should be a lot more reliable

@rebello95
Copy link
Collaborator

👍🏽 I'd definitely advise using Connect + URLSession if you don't strictly need to use the gRPC protocol - it's simpler and will also reduce your binary size.

If you want to debug further, the next steps I'd suggest are:

  • See if you can get any useful information out of ConnectError.message when the failure arises
  • Consider using a recent commit from Connect-Swift which includes this change, as it may give you a more helpful status depending on what the underlying error is
  • Consider implementing retries (you can do this inside of a Connect interceptor)
  • If possible, see if the issue persists with Connect + URLSession

@rebello95 rebello95 assigned aheze and unassigned rebello95 Jan 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants