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

Fix connection callback crashes when reloading with React Native #7936

Closed
wants to merge 0 commits into from

Conversation

gagik
Copy link
Contributor

@gagik gagik commented Jul 31, 2024

What, How & Why?

See realm/realm-js#6579 and realm/realm-js#6824
When hot reloading with React Native and using sync session connection change callbacks, the app crashes. This is because the callbacks are not cleared and get called. This PR attempts to fix it.

My solution has been to add some form of clear_all_callbacks and run in either always when abruptly stopping sync sessions or in a specific newly exposed function.

There may be better alternatives but hopefully this will showcase the issue better. The changes do make the crashes more rare but if made quickly enough, the app can still crash. This other crash has no stack trace so it's much harder to debug but may be related to some mistake being made here.

☑️ ToDos

  • 📝 Changelog update
  • 🚦 Tests (or not relevant)
  • C-API, if public C++ API changed
  • bindgen/spec.yml, if public C++ API changed

@cla-bot cla-bot bot added the cla: yes label Jul 31, 2024
@gagik gagik force-pushed the gagik/fix-connection-callback-crashes branch from bdee157 to 953e657 Compare July 31, 2024 15:28
@@ -224,8 +229,10 @@ void SyncSession::do_become_inactive(util::CheckedUniqueLock lock, Status status

// Send notifications after releasing the lock to prevent deadlocks in the callback.
if (old_state != new_state) {
m_connection_change_notifier.invoke_callbacks(old_state, connection_state());
// m_connection_change_notifier.invoke_callbacks(old_state, connection_state());
Copy link
Contributor Author

Choose a reason for hiding this comment

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

So this is the problem here... I am not sure if this is some race condition of sort but even just commenting this out makes the crashes at least 50% less rare on hot reload (I realize this is useful in all other scenarios so it shouldn't stay like this, just not sure how to tackle that).

}
m_connection_change_notifier.clear_callbacks();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This basically fixes these crashes completely

@@ -397,6 +397,25 @@ void SyncManager::close_all_sessions()
get_sync_client().wait_for_session_terminations();
}


void SyncManager::clear_connection_change_callbacks()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

One idea I had was to expose this through the app and manually run that the way we do clearAllAppCaches in this code it isn't yet exposed.

Copy link
Collaborator

Choose a reason for hiding this comment

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

have you tried using this (or close_all_sessions())? I am curious if React Native waits for it to complete.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe I have but will re-check now

Copy link
Contributor Author

@gagik gagik Aug 7, 2024

Choose a reason for hiding this comment

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

@danieltabacaru I have actually been running close_all_sessions as App::close_all_sync_sessions calls this and eventually this hits the become_dying > become_inactive > do_become_inactive function I have been modifying. Without the changes in the PR I don't think the listeners are actually removed, at least not on time

It actually may be awaiting this close_all_sync_sessions call as it gets made in the start of loading the new state after reload rather than the end of the old one so if the function is blocking correctly I believe it should await.

You can see the JS side of things here: realm/realm-js#6824

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think I finally understand what's going on. When the app reloads, the connection callback of an old SyncSession is invoked, but the callback is long gone (and hence the crash). Does this sound right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@danieltabacaru Yes exactly


m_callbacks.clear();
m_callback_count = 0;
m_callback_index = npos; // Reset callback index since all callbacks are removed
Copy link
Contributor Author

@gagik gagik Jul 31, 2024

Choose a reason for hiding this comment

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

There may be a better way to do this

@danieltabacaru danieltabacaru force-pushed the gagik/fix-connection-callback-crashes branch from 953e657 to 819bb98 Compare August 7, 2024 15:42
Copy link

Pull Request Test Coverage Report for Build github_pull_request_301264

Details

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • 165 unchanged lines in 23 files lost coverage.
  • Overall coverage increased (+0.009%) to 91.111%

Files with Coverage Reduction New Missed Lines %
src/realm/util/file.cpp 1 84.84%
test/fuzz_tester.hpp 1 57.73%
test/test_dictionary.cpp 1 99.83%
src/realm/cluster.cpp 2 75.85%
src/realm/db.cpp 2 92.19%
src/realm/sync/network/http.hpp 2 82.27%
src/realm/sync/noinst/client_reset.cpp 3 94.5%
src/realm/sync/instructions.hpp 4 76.2%
src/realm/sync/transform.cpp 4 60.92%
src/realm/table.cpp 4 90.42%
Totals Coverage Status
Change from base Build 2546: 0.009%
Covered Lines: 216840
Relevant Lines: 237996

💛 - Coveralls

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 6, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants