I'm upgrading my RN app from 0.56 to 0.59.3 and decided to move back to the community AsyncStorage solution. The problem I'm running into is that the serial Executor is getting jammed up processing getKey requests after about the 3rd request for a getKey. The result is in the JS side, the Promise never returns and locks up the app.
The Serial Executor in use by the AsyncStorage solution would process the AsyncStorage request or fail but not go into a locked up state.
In my RN app, I have 4 AsyncStorage getKey requests during startup which all happen in succession. I've never seen the 4th request return. Sometimes I'll see requests 1-3 return before it hangs on the 4th. This happens on the Simulator and on the device. I've only tested on Android 9 sim and Pixel 2 Android 9.
To point to the Serial Executor as the problem, I removed all references to the Serial Executor in the AsyncStorage code base and just let the SQL Lite requests run on the main thread and it works perfectly.
@wfilleman Hey,
Thanks for reporting this. This is interesting case, seems like serial executor chokes on multiple calls. Did you try it on other Android versions (before Pie)?
And by I have 4 AsyncStorage getKey requests during startup getKey you mean getItem right?
thanks.
Hi @Krizzu ,
I just tried this on Android 8 emulator and saw the same lockup results. And yes, thank you, I meant getItem.
Wes
@wfilleman
I've tried to replicate situation like you mention. I had 4 consequent getItem requests, but every time I'm able to retrieve and save a value, using promises and callbacks.
Can you provide some repro steps that's allow me to have a look? Is there a chance that some of your getItem throws and you're not handling it? (meaning rest of them are not called).
thanks.
I've got the exact same problem, here is my implementation, inside a componentDidMount.
async componentDidMount() {
const { tryLogin: loginFromFirstScreen } = this.props
try {
const sessionToken = await AsyncStorage.getItem('@PicStore:token')
if (sessionToken) {
loginFromFirstScreen('', '', sessionToken)
}
} catch (error) {
console.log(
`Error while reading from async storage ${error.name}: ${error.message}`
)
}
}
Tested on Android Pie (One Plus 6T).
I start getting the Maximum call stack size exceeded error.
Hi @Krizzu, similar to @theolavaux my implementation is very simple:
export async function loadAllAccounts() {
console.log('loadAllAccounts');
const accounts = (await AsyncStorage.getItem('Accounts')) || '{}';
console.log('AsyncStorage Returned');
store.setters.setAllAccounts(JSON.parse(accounts));
}
The logging is there so I can track when AsyncStorage returns and when it gets lost on the native side. The caller's "catch" is never executed. When I debugged this on the native side, the serial executor is hung up. It never executes and never throws an error.
Something I'm not sure how to capture or show is I'm also using Parse and Parse Server. The Parse client uses AsyncStorage as well and is actively trying to retrieve values from AsyncStorage in parallel to the rest of my RN app starting up as part of the Parse Client SDK internals. So, for sure, there are parallel requests to AsyncStorage happening and not just a clean promise chain of gets.
Wes
I'm going to keep in mind that issue while improving implementation for v2.
Adding this to refs in #133
@Krizzu FYI the new AsyncStorage_dedicatedExecutor=true in gradle.properties with AsyncStorage 1.6.1 seems to have fixed this issue I was experiencing on Android. Thank you for making this an option!
Glad you found that useful :)