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

execute calls to AsyncStorageModule serially #20386

Closed
wants to merge 11 commits into from

Conversation

dulmandakh
Copy link
Contributor

@dulmandakh dulmandakh commented Jul 25, 2018

This PR creates single threaded executor in AsyncStorageModule and use it to execute calls serially, so that below code works as expected

await AsyncStorage.setItem('foo', 'bar');
await AsyncStorage.getItem('foo').then(console.log); // 'bar'
await AsyncStorage.getAllKeys().then(console.log); // ['foo']

Previously, it was using AsyncTask that executes tasks in its own thread pool, which may execute calls in parallel.

Since it uses its own executor, it don't need to wrap the executions in the AsyncTask.

Fixes #18372 #14101

Test Plan:

Before (it's inconsistent)

await AsyncStorage.setItem('foo', 'bar');
await AsyncStorage.getItem('foo').then(console.log); // null
await AsyncStorage.getAllKeys().then(console.log); // []

After

await AsyncStorage.setItem('foo', 'bar');
await AsyncStorage.getItem('foo').then(console.log); // 'bar'
await AsyncStorage.getAllKeys().then(console.log); // ['foo']

Release Notes:

Help reviewers and the release process by writing your own release notes. See below for an example.

[ANDROID] [BUGFIX] [AsyncStorage] - Execute calls serially

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jul 25, 2018
@dulmandakh
Copy link
Contributor Author

@hramos @gengjiawen I have no experience of writing android tests, could you please help update tests for AsyncStorageModule?

@@ -1,4 +1,4 @@
/**
/*
Copy link
Contributor

@gengjiawen gengjiawen Jul 26, 2018

Choose a reason for hiding this comment

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

why touch this line ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Android Studio was showing warning, so fixed it 😄

@gengjiawen
Copy link
Contributor

I have little test experience on android test. Do you test your code in some way , like tested it on real device.

@dulmandakh
Copy link
Contributor Author

dulmandakh commented Jul 26, 2018 via email

@gengjiawen
Copy link
Contributor

I find flow difficulty to write too. I want it in plain js. And also current project has to many #FlowFixme.

@@ -83,9 +85,9 @@ public void multiGet(final ReadableArray keys, final Callback callback) {
return;
}

new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
execute(new Runnable() {
Copy link
Contributor

Choose a reason for hiding this comment

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

What happens if an exception is thrown when executing the Runnable?

GuardedAsyncTask provided error management, see: https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/GuardedAsyncTask.java#L34

Copy link
Contributor

Choose a reason for hiding this comment

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

Could we use executeOnExecutor (https://developer.android.com/reference/android/os/AsyncTask.html#executeOnExecutor(java.util.concurrent.Executor,%20Params...)) instead of execute and keep using GuardedAsyncTask instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@janicduplessis got it and ready to push the change, but waiting for CI to become green again.

@@ -42,6 +43,7 @@

private ReactDatabaseSupplier mReactDatabaseSupplier;
private boolean mShuttingDown = false;
private Executor executor = Executors.newSingleThreadExecutor();
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure if adding a new executor is the best approach here, but If you are adding this you should override the onCatalystInstanceDestroy method and then shutdown the executor.
See:

@dulmandakh
Copy link
Contributor Author

dulmandakh commented Jul 29, 2018 via email

@dulmandakh
Copy link
Contributor Author

dulmandakh commented Jul 30, 2018

@mdvacca made changes as you suggested 😉

@dulmandakh
Copy link
Contributor Author

ExecutorService in AsyncStorageModule is customizable, and test is passing. It'll fix many issues on Android, including me.

@mdvacca please review and merge

dulmandakh referenced this pull request Jul 31, 2018
Summary:
This patch is a bit of a hack job, but I'd argue it's necessary to dramatically improve the dev UX on Android devices. Somewhere in react-native, there's a shared SerialExecutor which AsyncStorage uses that is getting blocked, causing remote debugging to occasionally hang indefinitely for folks making AsyncStorage requests. This is frustrating from a dev UX perspective, and has persisted across several versions as far back as RN 0.44, and still remains on RN 0.54.

The issue seems to only happen on Android > 7+, which is likely because the ThreadPoolExecutor behavior changed in this version:
https://stackoverflow.com/questions/9654148/android-asynctask-threads-limits

Fixes #14101

We've been using this patch in production for the past 4 months on our team by overriding the AsyncStorage native module. We use AsyncStorage extensively for offline data and caching.

You can test by compiling this commit version into a test react native repository that is set to build from source:

```sh
git clone https://github.com/dannycochran/react-native rnAsyncStorage
cd rnAsyncStorage
git checkout asyncStorage
cd ..
git clone https://github.com/dannycochran/asyncStorageTest
yarn install
cp -r ../rnAsyncStorage node_modules/react-native
react-native run-android
```

No documentation change is required.

#16905

[Android] [BUGFIX] [AsyncStorage] - Fix AsyncStorage causing remote debugger to hang indefinitely.
Pull Request resolved: #18522

Differential Revision: D8624088

Pulled By: hramos

fbshipit-source-id: a1d2e3458d98467845cb34ac73f2aafaaa15ace2
@dulmandakh dulmandakh requested a review from hramos July 31, 2018 02:15
@gengjiawen
Copy link
Contributor

Maybe add RNTester showcase too. Can we just add plain js in RNTester ? @hramos @janicduplessis

@hramos
Copy link
Contributor

hramos commented Aug 17, 2018

I'll wait for @mdvacca to provide feedback here. Also, looks like we have some conflicts.

Copy link
Contributor

@hramos hramos left a comment

Choose a reason for hiding this comment

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

Fix conflicts.

@dulmandakh
Copy link
Contributor Author

dulmandakh commented Aug 23, 2018

@hramos @janicduplessis please review and merge. CI fails on E2E due to timeout. Thank you

@hramos
Copy link
Contributor

hramos commented Aug 23, 2018

CI looks good, still waiting on review from @mdvacca or other. I'm not the best person to review this.

@dulmandakh
Copy link
Contributor Author

@mdvacca could you please review ASAP. I would like it to land in 0.57 if possible, because I'm planning to use it for my projects. Thank you

@ahilles107
Copy link

Would be great to have it in 0.57!

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

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

hramos has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@dulmandakh dulmandakh closed this Nov 1, 2018
@dulmandakh dulmandakh reopened this Nov 1, 2018
@dulmandakh dulmandakh closed this Nov 2, 2018
@dulmandakh dulmandakh reopened this Nov 2, 2018
@dulmandakh dulmandakh closed this Nov 2, 2018
@dulmandakh dulmandakh reopened this Nov 2, 2018
@hramos hramos added Core Team and removed Core Team labels Feb 1, 2019
@cpojer
Copy link
Contributor

cpojer commented Feb 11, 2019

Hey @dulmandakh. We moved AsyncStorage to its own repo, it would be great if you could re-send your PR to that one: https://github.com/react-native-community/react-native-async-storage

@cpojer cpojer closed this Feb 11, 2019
@dulmandakh dulmandakh deleted the serial-asyncstorage branch October 15, 2019 05:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Platform: Android Android applications.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants