Skip to content

Reset backoff when connectivity status changes #5857

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

Merged
merged 7 commits into from
Jun 22, 2020

Conversation

schmidt-sebastian
Copy link
Contributor

@schmidt-sebastian schmidt-sebastian commented Jun 19, 2020

This is a follow up to #4985 and addresses an additional problem that I saw in the test app. If the SDK was already in the background and we were in a backoff phase, the SDK waited for the backoff to finish before reconnecting, which could take up to a minute. This PR plumbs the connectivity handler through to RemoteStore and resets the backoff when a connectivity change occurred.

cc @wu-hui

Fixes #5783

@schmidt-sebastian schmidt-sebastian changed the title Reset backoff if connectivity status changed WIP Reset backoff if connectivity status changed Jun 19, 2020
@schmidt-sebastian schmidt-sebastian changed the title WIP Reset backoff if connectivity status changed Reset backoff when connectivity status changes Jun 19, 2020
Copy link
Contributor

@var-const var-const left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to test the new behavior? (I think all existing tests that emulate connectivity changes are in test/unit/remote/grpc_connection_test.cc, see if it's possible to write similar tests for this)

@@ -1,3 +1,8 @@
# Unreleased
- [fixed] Removed a delay that may have prevented Firestore from immediately
establishing a network connections if a connectivity change occurred while
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: either "a network connection" or "network connections".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Datastore::Datastore(const DatabaseInfo& database_info,
const std::shared_ptr<AsyncQueue>& worker_queue,
std::shared_ptr<CredentialsProvider> credentials,
std::unique_ptr<ConnectivityMonitor> connectivity_monitor)
ConnectivityMonitor* connectivity_monitor)
: worker_queue_{NOT_NULL(worker_queue)},
credentials_{std::move(credentials)},
rpc_executor_{CreateExecutor()},
connectivity_monitor_{std::move(connectivity_monitor)},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this move is now extraneous (moving a built-in, such as a pointer, is the same as copying it).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@@ -59,13 +59,15 @@ using util::Status;
constexpr int kMaxPendingWrites = 10;

RemoteStore::RemoteStore(
LocalStore* local_store,
local::LocalStore* local_store,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: qualifying LocalStore with its namespace shouldn't be necessary given the using directive above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

if (CanUseNetwork()) {
LOG_DEBUG("RemoteStore %s restarting streams as connectivity changed",
this);
RestartNetwork();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't create any undesirable interactions with the existing logic on connectivity change, right? (I don't think it should, just checking)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The existing logic invalidates the GRPC channel, which speeds up reconnects already and is the foundation this PR is based on.

@@ -77,6 +79,15 @@ void RemoteStore::Start() {
// For now, all setup is handled by `EnableNetwork`. We might expand on this
// in the future.
EnableNetwork();

connectivity_monitor_->AddCallback(
[this](ConnectivityMonitor::NetworkStatus /*ignored*/) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary/desirable to run this logic when the network status is "unavailable"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not - but note that

kills the GRPC channel no matter what.

DisableNetworkInternal();
online_state_tracker_.UpdateState(OnlineState::Unknown);
EnableNetwork();
RestartNetwork();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this PR could also make reconnection faster upon credentials' change? If correct, perhaps it's worth mentioning in the PR's description?

Copy link
Contributor Author

@schmidt-sebastian schmidt-sebastian Jun 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only if the credential change happened while offline, which is probably uncommon (since Auth needs a network connection as well).

Copy link
Contributor Author

@schmidt-sebastian schmidt-sebastian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I addressed the easy comments.

I don't know how to unit test this - let's talk about this on Monday. This code affects the RemoteStore, so we should test it there. The only tests for the RemoteStore, however, are the Spec tests, which right now don't handle connectivity. I think writing a unit test would entail porting this PR to Web and then adding the credential change listener to the Spec tests suite. That's something we can do, but maybe we can come up with an easier and more direct way to test.

In the meantime, I will verify via test app that my recent change to ignore Unavailable didn't affect the functionality.

@@ -1,3 +1,8 @@
# Unreleased
- [fixed] Removed a delay that may have prevented Firestore from immediately
establishing a network connections if a connectivity change occurred while
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Datastore::Datastore(const DatabaseInfo& database_info,
const std::shared_ptr<AsyncQueue>& worker_queue,
std::shared_ptr<CredentialsProvider> credentials,
std::unique_ptr<ConnectivityMonitor> connectivity_monitor)
ConnectivityMonitor* connectivity_monitor)
: worker_queue_{NOT_NULL(worker_queue)},
credentials_{std::move(credentials)},
rpc_executor_{CreateExecutor()},
connectivity_monitor_{std::move(connectivity_monitor)},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@@ -59,13 +59,15 @@ using util::Status;
constexpr int kMaxPendingWrites = 10;

RemoteStore::RemoteStore(
LocalStore* local_store,
local::LocalStore* local_store,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@@ -77,6 +79,15 @@ void RemoteStore::Start() {
// For now, all setup is handled by `EnableNetwork`. We might expand on this
// in the future.
EnableNetwork();

connectivity_monitor_->AddCallback(
[this](ConnectivityMonitor::NetworkStatus /*ignored*/) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not - but note that

kills the GRPC channel no matter what.

if (CanUseNetwork()) {
LOG_DEBUG("RemoteStore %s restarting streams as connectivity changed",
this);
RestartNetwork();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The existing logic invalidates the GRPC channel, which speeds up reconnects already and is the foundation this PR is based on.

DisableNetworkInternal();
online_state_tracker_.UpdateState(OnlineState::Unknown);
EnableNetwork();
RestartNetwork();
Copy link
Contributor Author

@schmidt-sebastian schmidt-sebastian Jun 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only if the credential change happened while offline, which is probably uncommon (since Auth needs a network connection as well).

Copy link
Contributor

@var-const var-const left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that testing this is a hard problem, so I don't want to block this PR on that (it can be done in a follow-up, and for now doing manual testing seems sufficient).

@schmidt-sebastian
Copy link
Contributor Author

Verified manually.

@schmidt-sebastian schmidt-sebastian merged commit 296a1ea into master Jun 22, 2020
@schmidt-sebastian schmidt-sebastian deleted the mrschmidt/backoff branch June 22, 2020 22:49
@firebase firebase locked and limited conversation to collaborators Jul 23, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Firestore connection delays when enables WiFi in background
4 participants