-
Notifications
You must be signed in to change notification settings - Fork 420
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
Stream stops receiving messages after changing connection from Wifi to Cellular #337
Comments
SwiftGRPC is using gRPC-Core, which is using BSD sockets under the hood (I think). It might be that these never get notified of the switch to cellular or don't cause the cellular radio get turned on (there was a discussion about this once in the SwiftNIO Github repo).
Unfortunately, I don't know of a good solution to that besides your workaround. A NIO-based client implementation might do better in that regard (but only on iOS 12), but is still a while out and I can't tell yet whether that would really work better.
… On 3. Dec 2018, at 13:01, Slava Bulgakov ***@***.***> wrote:
Question Checklist
Updated grpc-swift to the latest version
I read the Contribution Guidelines
I read README
I searched for existing GitHub issues (especially, there are many resolved issues related to SSL)
Question Subject
How to restart a stream after changing connection from Wifi to Cellular?
Question Description
I use SwiftGRPC in iOS app and I have the client like:
service UpdateService {
rpc GetUpdates (UpdatesConnection) returns (stream Update);
}
I subscribe on connectivity state of channel:
updateClient.channel.subscribe { connectivityState in
...
}
Then I make request to create stream from server:
let call = try updateClient.getUpdates(UpdatesConnection()) { result in
switch result.statusCode {
…
}
}
When I change iPhone connection from Wifi to Cellular, the stream stops receiving messages from server but the connectivityState (subscription to connectivity state) and result.statusCode keeping silent. After few minutes connectivityState gets .idle and result.statusCode gets . unavailable. When result.statusCode gets . unavailable I trying to call let call = try updateClient.getUpdates(UpdatesConnection()) again, but stream doesn't receive messages anyway.
So I've added subscription on iOS network state (Reachability) and I destroy the updateClient and recreate it when connection get changed from WIfi to Cellular. Only after destroying and recreating the updateClient the stream works properly - it receive messages.
Am I doing right? Maybe my way is wrong and there is another way to restart stream after changing connection?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
Addresses grpc#198. It's currently not possible to manually shut down a gRPC channel, which means that the only way to shut down a channel is to deallocate it. This requirement is a bit fragile for cases where a consumer wants to manually shut down a channel, since it requires confidence that nothing else is holding a strong reference to the channel. This PR: - Adds a `shutdown` function to `Channel`, allowing consumers to arbitrarily shut down connections - Validates that existing calls will throw errors when attempting to read/write from a previously shut down channel - Ensures creating new calls using previously shut down channels will result in the initializer throwing (already handled by code generators) This change is increasingly relevant because consumers will need to shut down channels and restart them to help mitigate issues when switching between wifi/cellular as mentioned here: grpc#337.
The current issue is extensively problematic because end consumers/calls are never notified if a connection goes offline. Instead, gRPC streams/channels stay active even though they're silently offline (though not destroyed). This can result in streams appearing to hang. I was talking to @MrMage offline earlier today about this, and there are a few ideas for how we can potentially make this a bit easier for consumers to handle (though it's not possible to solve the problem altogether as long as we're using gRPC-Core for reasons outlined above).
None of these options are super ideal. At the moment, I'm leaning towards option Planning to investigate this a bit more tomorrow, and I'm curious to hear other thoughts! |
@rebello95 You can to setup keep alive https://github.com/grpc/grpc-go/blob/master/examples/features/keepalive/server/main.go#L44 so server pings client and automatically closes the connection if client is offline. |
I agree that how one wants to handle this would probably be very application-specific, so letting users control the process should be advisable. We might want to provide guidance or suggestions on a "best practice" to handle this (possibly with a simple, optional class that can do this for the user), but give the user to handle this themselves in a custom fashion if desired. |
Addresses grpc#198. It's currently not possible to manually shut down a gRPC channel, which means that the only way to shut down a channel is to deallocate it. This requirement is a bit fragile for cases where a consumer wants to manually shut down a channel, since it requires confidence that nothing else is holding a strong reference to the channel. This PR: - Adds a `shutdown` function to `Channel`, allowing consumers to arbitrarily shut down connections - Validates that existing calls will throw errors when attempting to read/write from a previously shut down channel - Ensures creating new calls using previously shut down channels will result in the initializer throwing (already handled by code generators) This change is increasingly relevant because consumers will need to shut down channels and restart them to help mitigate issues when switching between wifi/cellular as mentioned here: grpc#337.
Addresses grpc#198. It's currently not possible to manually shut down a gRPC channel, which means that the only way to shut down a channel is to deallocate it. This requirement is a bit fragile for cases where a consumer wants to manually shut down a channel, since it requires confidence that nothing else is holding a strong reference to the channel. This PR: - Adds a `shutdown` function to `Channel`, allowing consumers to arbitrarily shut down connections - Cancels all existing calls that are using the channel upon shutdown - Validates that existing calls will throw errors when attempting to read/write from a previously shut down channel - Ensures creating new calls using previously shut down channels will result in the initializer throwing (already handled by code generators) This change is increasingly relevant because consumers will need to shut down channels and restart them to help mitigate issues when switching between wifi/cellular as mentioned here: grpc#337.
Addresses grpc#198. It's currently not possible to manually shut down a gRPC channel, which means that the only way to shut down a channel is to deallocate it. This requirement is a bit fragile for cases where a consumer wants to manually shut down a channel, since it requires confidence that nothing else is holding a strong reference to the channel. This PR: - Adds a `shutdown` function to `Channel`, allowing consumers to arbitrarily shut down connections - Cancels all existing calls that are using the channel upon shutdown - Validates that existing calls will throw errors when attempting to read/write from a previously shut down channel - Ensures creating new calls using previously shut down channels will result in the initializer throwing (already handled by code generators) This change is increasingly relevant because consumers will need to shut down channels and restart them to help mitigate issues when switching between wifi/cellular as mentioned here: grpc#337.
Sounds good. I'll go ahead and do the following:
|
We've only just started looking into GRPC on mobile and have been running into this problem as well. Most often it is the case either if changing from WiFi to Cellular (or back) and/or if the (WiFi/cellular) signal gets weak. It seems that |
* Add ability to manually shut down channels Addresses #198. It's currently not possible to manually shut down a gRPC channel, which means that the only way to shut down a channel is to deallocate it. This requirement is a bit fragile for cases where a consumer wants to manually shut down a channel, since it requires confidence that nothing else is holding a strong reference to the channel. This PR: - Adds a `shutdown` function to `Channel`, allowing consumers to arbitrarily shut down connections - Cancels all existing calls that are using the channel upon shutdown - Validates that existing calls will throw errors when attempting to read/write from a previously shut down channel - Ensures creating new calls using previously shut down channels will result in the initializer throwing (already handled by code generators) This change is increasingly relevant because consumers will need to shut down channels and restart them to help mitigate issues when switching between wifi/cellular as mentioned here: #337. * CR * try! -> try * support linux * CR
The SwiftGRPC implementation that is backed by [gRPC-Core](https://github.com/grpc/grpc) (and not SwiftNIO) is known to have some connectivity issues on iOS clients - namely, silently disconnecting (making it seem like active calls/connections are hanging) when switching between wifi <> cellular. The root cause of these problems is that the backing gRPC-Core doesn't get the optimizations made by iOS' networking stack when these types of changes occur, and isn't able to handle them itself. To aid in this problem, we're adding a [`ClientNetworkMonitor`](./Sources/SwiftGRPC/Core/ClientNetworkMonitor.swift) that monitors the device for events that can cause gRPC to disconnect silently. We recommend utilizing this component to call `shutdown()` (or destroy) any active `Channel` instances, and start new ones when the network is reachable. Details: - **Switching between wifi <> cellular:** Channels silently disconnect - **Network becoming unreachable:** Most times channels will time out after a few seconds, but `ClientNetworkMonitor` will notify of these changes much faster - **Switching between background <> foreground:** No known issues Original issue: grpc#337.
Yep @markschmid setting that would probably help with connectivity issues, but likely won't be very quick to notify you of those problems since the connection would have to time out first. |
Implemented the |
The SwiftGRPC implementation that is backed by [gRPC-Core](https://github.com/grpc/grpc) (and not SwiftNIO) is known to have some connectivity issues on iOS clients - namely, silently disconnecting (making it seem like active calls/connections are hanging) when switching between wifi <> cellular. The root cause of these problems is that the backing gRPC-Core doesn't get the optimizations made by iOS' networking stack when these types of changes occur, and isn't able to handle them itself. To aid in this problem, we're adding a [`ClientNetworkMonitor`](./Sources/SwiftGRPC/Core/ClientNetworkMonitor.swift) that monitors the device for events that can cause gRPC to disconnect silently. We recommend utilizing this component to call `shutdown()` (or destroy) any active `Channel` instances, and start new ones when the network is reachable. Details: - **Switching between wifi <> cellular:** Channels silently disconnect - **Network becoming unreachable:** Most times channels will time out after a few seconds, but `ClientNetworkMonitor` will notify of these changes much faster - **Switching between background <> foreground:** No known issues Original issue: grpc#337.
Also want to note that there's documentation of this behavior in the Objective-C implementation, and they took a similar approach to solving this problem (though it doesn't look like they handle the case of disconnecting when switching between |
The SwiftGRPC implementation that is backed by [gRPC-Core(https://github.com/grpc/grpc) (and not SwiftNIO) is known to have some connectivity issues on iOS clients - namely, silently disconnecting (making it seem like active calls/connections are hanging) when switching between wifi <> cellular. The root cause of these problems is that the backing gRPC-Core doesn't get the optimizations made by iOS' networking stack when these types of changes occur, and isn't able to handle them itself. There is also documentation of this behavior in [this gRPC-Core readme](https://github.com/grpc/grpc/blob/v1.19.0/src/objective-c/NetworkTransitionBehavior.md). To aid in this problem, we're adding a [`ClientNetworkMonitor`](./Sources/SwiftGRPC/Core/ClientNetworkMonitor.swift) that monitors the device for events that can cause gRPC to disconnect silently. We recommend utilizing this component to call `shutdown()` (or destroy) any active `Channel` instances, and start new ones when the network is reachable. Details: - **Switching between wifi <> cellular:** Channels silently disconnect - **Switching between 3G <> LTE (etc.):** Channels silently disconnect - **Network becoming unreachable:** Most times channels will time out after a few seconds, but `ClientNetworkMonitor` will notify of these changes much faster - **Switching between background <> foreground:** No known issues Original issue: #337.
Took a long ride this morning going around San Francisco evaluating how well iOS is able to maintain a gRPC connection. Things I noticed (pretty much confirming my comments above):
The changes that cause silent disconnects were caught by the observer I added in #387, so consumers should be able to resolve these issues by utilizing that. I also just issued a |
Going to close out this issue since it's now documented in the readme and there are workarounds on the latest release. Feel free to re-open with new concerns! |
Would update to gRPC-Core 1.13.0 dependency fix this issue?
https://github.com/grpc/grpc/blob/v1.19.0/src/objective-c/NetworkTransitionBehavior.md |
Simply updating to 1.13.0 wouldn't solve this problem. The CFStream implementation mentioned might fix this issue, but it's currently gated by compiler conditionals upstream since it's marked as "experimental". If we wanted to utilize it today in SwiftGRPC, we could theoretically add branching logic for using either CFStream or the existing gRPC-Core implementation, but this would be a bit challenging given we have to support Carthage, Swift PM, and CocoaPods. I do think that upgrading gRPC-Core to use this implementation when CFStream becomes the primary implementation upstream for iOS would be ideal, though! |
According to this README the CFStream implementation will be default as of 1.21.0 (which is the current in-development version) |
Any updates on this since gRPC-Core has already shipped with CFStream as default backend? |
We are still using gRPC-Core 1.19; I think CFStream is not yet enabled there. |
Correct, we aren't using a version of gRPC-Core with CFStream as the default. If you'd like to submit a PR updating, we're happy to review! |
We did smoke tests with version 0.10.0 and confirm that connectivityObserver is called when switching networks, while it doesn’t in version 0.8.0 |
* Add ability to manually shut down channels Addresses grpc/grpc-swift#198. It's currently not possible to manually shut down a gRPC channel, which means that the only way to shut down a channel is to deallocate it. This requirement is a bit fragile for cases where a consumer wants to manually shut down a channel, since it requires confidence that nothing else is holding a strong reference to the channel. This PR: - Adds a `shutdown` function to `Channel`, allowing consumers to arbitrarily shut down connections - Cancels all existing calls that are using the channel upon shutdown - Validates that existing calls will throw errors when attempting to read/write from a previously shut down channel - Ensures creating new calls using previously shut down channels will result in the initializer throwing (already handled by code generators) This change is increasingly relevant because consumers will need to shut down channels and restart them to help mitigate issues when switching between wifi/cellular as mentioned here: grpc/grpc-swift#337. * CR * try! -> try * support linux * CR
The SwiftGRPC implementation that is backed by [gRPC-Core(https://github.com/grpc/grpc) (and not SwiftNIO) is known to have some connectivity issues on iOS clients - namely, silently disconnecting (making it seem like active calls/connections are hanging) when switching between wifi <> cellular. The root cause of these problems is that the backing gRPC-Core doesn't get the optimizations made by iOS' networking stack when these types of changes occur, and isn't able to handle them itself. There is also documentation of this behavior in [this gRPC-Core readme](https://github.com/grpc/grpc/blob/v1.19.0/src/objective-c/NetworkTransitionBehavior.md). To aid in this problem, we're adding a [`ClientNetworkMonitor`](./Sources/SwiftGRPC/Core/ClientNetworkMonitor.swift) that monitors the device for events that can cause gRPC to disconnect silently. We recommend utilizing this component to call `shutdown()` (or destroy) any active `Channel` instances, and start new ones when the network is reachable. Details: - **Switching between wifi <> cellular:** Channels silently disconnect - **Switching between 3G <> LTE (etc.):** Channels silently disconnect - **Network becoming unreachable:** Most times channels will time out after a few seconds, but `ClientNetworkMonitor` will notify of these changes much faster - **Switching between background <> foreground:** No known issues Original issue: grpc/grpc-swift#337.
* Add ability to manually shut down channels Addresses grpc/grpc-swift#198. It's currently not possible to manually shut down a gRPC channel, which means that the only way to shut down a channel is to deallocate it. This requirement is a bit fragile for cases where a consumer wants to manually shut down a channel, since it requires confidence that nothing else is holding a strong reference to the channel. This PR: - Adds a `shutdown` function to `Channel`, allowing consumers to arbitrarily shut down connections - Cancels all existing calls that are using the channel upon shutdown - Validates that existing calls will throw errors when attempting to read/write from a previously shut down channel - Ensures creating new calls using previously shut down channels will result in the initializer throwing (already handled by code generators) This change is increasingly relevant because consumers will need to shut down channels and restart them to help mitigate issues when switching between wifi/cellular as mentioned here: grpc/grpc-swift#337. * CR * try! -> try * support linux * CR
The SwiftGRPC implementation that is backed by [gRPC-Core(https://github.com/grpc/grpc) (and not SwiftNIO) is known to have some connectivity issues on iOS clients - namely, silently disconnecting (making it seem like active calls/connections are hanging) when switching between wifi <> cellular. The root cause of these problems is that the backing gRPC-Core doesn't get the optimizations made by iOS' networking stack when these types of changes occur, and isn't able to handle them itself. There is also documentation of this behavior in [this gRPC-Core readme](https://github.com/grpc/grpc/blob/v1.19.0/src/objective-c/NetworkTransitionBehavior.md). To aid in this problem, we're adding a [`ClientNetworkMonitor`](./Sources/SwiftGRPC/Core/ClientNetworkMonitor.swift) that monitors the device for events that can cause gRPC to disconnect silently. We recommend utilizing this component to call `shutdown()` (or destroy) any active `Channel` instances, and start new ones when the network is reachable. Details: - **Switching between wifi <> cellular:** Channels silently disconnect - **Switching between 3G <> LTE (etc.):** Channels silently disconnect - **Network becoming unreachable:** Most times channels will time out after a few seconds, but `ClientNetworkMonitor` will notify of these changes much faster - **Switching between background <> foreground:** No known issues Original issue: grpc/grpc-swift#337.
Question Checklist
Question Subject
How to restart a stream after changing connection from Wifi to Cellular?
Question Description
I use SwiftGRPC in iOS app and I have the client like:
I subscribe on connectivity state of channel:
Then I make request to create stream from server:
When I change iPhone connection from Wifi to Cellular, the stream stops receiving messages from server but the
connectivityState
(subscription to connectivity state) andresult.statusCode
keeping silent. After few minutesconnectivityState
gets.idle
andresult.statusCode
gets. unavailable
. Whenresult.statusCode
gets. unavailable
I trying to calllet call = try updateClient.getUpdates(UpdatesConnection())
again, but stream doesn't receive messages anyway.So I've added subscription on iOS network state (Reachability) and I destroy the
updateClient
and recreate it when connection get changed from WIfi to Cellular. Only after destroying and recreating theupdateClient
the stream works properly - it receive messages.Am I doing right? Maybe my way is wrong and there is another way to restart stream after changing connection?
The text was updated successfully, but these errors were encountered: