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

[Android] Cannot perform this operation because there is no current transaction #800

Open
1 of 5 tasks
ball-hayden opened this issue May 2, 2022 · 27 comments
Open
1 of 5 tasks
Labels
bug Something isn't working help wanted :octocat: need info Need more information from the author

Comments

@ball-hayden
Copy link

ball-hayden commented May 2, 2022

What happened?

Error reporting shows the following message:

Cannot perform this operation because there is no current transaction

Version

1.17.3

What platforms are you seeing this issue on?

  • Android
  • iOS
  • macOS
  • Windows
  • web

System Information

System:
    OS: macOS 12.1
    CPU: (10) arm64 Apple M1 Pro
    Memory: 614.19 MB / 32.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 16.14.0 - /var/folders/cg/cnx9y_d15jq3tw07562by7zw0000gn/T/yarn--1651482100494-0.5048468084106195/node
    Yarn: 1.22.17 - /var/folders/cg/cnx9y_d15jq3tw07562by7zw0000gn/T/yarn--1651482100494-0.5048468084106195/yarn
    npm: 8.4.0 - ~/development/PlayerData/app/node_modules/.bin/npm
    Watchman: 2022.03.14.00 - /opt/homebrew/bin/watchman
  Managers:
    CocoaPods: 1.11.3 - /Users/hayden/.gem/ruby/3.0.2/bin/pod
  SDKs:
    iOS SDK:
      Platforms: DriverKit 21.4, iOS 15.4, macOS 12.3, tvOS 15.4, watchOS 8.5
    Android SDK: Not Found
  IDEs:
    Android Studio: 2021.1 AI-211.7628.21.2111.8309675
    Xcode: 13.3.1/13E500a - /usr/bin/xcodebuild
  Languages:
    Java: 11.0.15 - /usr/bin/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: ^18.0.0 => 18.0.0
    react-native: 0.66.4 => 0.66.4
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Steps to Reproduce

Unable to reproduce.

@ball-hayden ball-hayden added the bug Something isn't working label May 2, 2022
@ball-hayden ball-hayden reopened this May 6, 2022
@krizzu
Copy link
Member

krizzu commented May 9, 2022

Hey, could you please provide move info? What code you use/when? Do you have repro steps?

@ball-hayden
Copy link
Author

Hi @krizzu.

Sorry - we don't have any repro steps at all.
It's something we're seeing occasionally through error reporting (Sentry).

We use RNAsyncStorage alongside apollo-cache-persist, and this tends to be where we're seeing the error reported:

[apollo-cache-persist] Error persisting cache Error: Cannot perform this operation because there is no current transaction.
{
arguments: ["[apollo-cache-persist]","Error persisting cache",{}], 
logger: console
}

Probably not massively interesting, but for context our instanciation of apollo-cache-persist:

import AsyncStorage from '@react-native-async-storage/async-storage';
import { CachePersistor, AsyncStorageWrapper } from 'apollo3-cache-persist';

const cachePersistor = new CachePersistor({
  cache,
  storage: new AsyncStorageWrapper(AsyncStorage),
  debounce: 0,
});
cachePersistor.restore();

Apollo Cache Persist interacts using getItem, setItem, and removeItem, as you would expect:
https://github.com/apollographql/apollo-cache-persist/blob/master/src/storageWrappers/AsyncStorageWrapper.ts

@krizzu
Copy link
Member

krizzu commented May 23, 2022

Are you using Next storage implementation? If not, I might suspect that this would happen if you db would be accessed after Activity is destroyed (app is about to close). We have this code in on host destroy, which was placed there to fix other issue

@ball-hayden
Copy link
Author

Are you using Next storage implementation?

I'm not sure what you mean by this - sorry.

@krizzu
Copy link
Member

krizzu commented May 24, 2022

There's this feature to use different driver for storage (Android only, more details here)

@ball-hayden
Copy link
Author

Ah, thank you.
No - we're not using that.

@krizzu
Copy link
Member

krizzu commented May 25, 2022

In that case, my suspect would be to what I already said above

I might suspect that this would happen if you db would be accessed after Activity is destroyed (app is about to close). We have this code in on host destroy, which was placed there to fix other issue

Can't really tell why/when apollo does storage flush, but maybe it's on going to background?
That's a tough one, especially without solid repro steps

@ball-hayden
Copy link
Author

Yeah - that sounds sensible.
I'll see if I can get a reproduction together.

@WtfLaika
Copy link

WtfLaika commented May 26, 2022

I have same issue only with react-native-async-storage. I have implemented even next storage, but it didn't help. The way to reproduce is next: try to open and close your app 3-7 times(at startup must be implemented async storage) and you will get Error storing data [Error: Cannot perform this operation because there is no current transaction.]

System info:

 OS: macOS 12.0.1
    CPU: (8) arm64 Apple M1
    Memory: 97.69 MB / 8.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 18.2.0 - /var/folders/qy/wpyxmffx3l152qq1hgt2j00m0000gn/T/yarn--1653581044654-0.7297387852884578/node
    Yarn: 1.22.18 - /var/folders/qy/wpyxmffx3l152qq1hgt2j00m0000gn/T/yarn--1653581044654-0.7297387852884578/yarn
    npm: 8.10.0 - /opt/homebrew/bin/npm
    Watchman: 2022.05.16.00 - /opt/homebrew/bin/watchman
  Managers:
    CocoaPods: 1.11.2 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: DriverKit 21.4, iOS 15.5, macOS 12.3, tvOS 15.4, watchOS 8.5
    Android SDK: Not Found
  IDEs:
    Android Studio: 2021.2 AI-212.5712.43.2112.8512546
    Xcode: 13.4/13F17a - /usr/bin/xcodebuild
  Languages:
    Java: 11.0.15 - /usr/bin/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: 17.0.2 => 17.0.2 
    react-native: 0.65.1 => 0.65.1 
    react-native-macos: Not Found

gradle.properties:

AsyncStorage_useNextStorage=true
AsyncStorage_kotlinVersion=1.6.10
AsyncStorage_next_roomVersion=2.4.2
AsyncStorage_db_size_in_MB=100

@krizzu
Copy link
Member

krizzu commented May 26, 2022

try to open and close your app 3-7 times(at startup must be implemented async storage) and you will get Error storing data [Error: Cannot perform this operation because there is no current transaction.]

Can you please add specific code + where you want it? index.js / App component etc.

@WtfLaika
Copy link

try to open and close your app 3-7 times(at startup must be implemented async storage) and you will get Error storing data [Error: Cannot perform this operation because there is no current transaction.]

Can you please add specific code + where you want it? index.js / App component etc.

function LaunchScreen({navigation}: LaunchProps) {
  const dispatch = useDispatch();

  useEffect(() => {
    const clearUserOnFirstRun = async () => {
      try {
        const key = '@first_run_complete';
        const value = await AsyncStorage.getItem(key);
        console.log('value', value);
        if (value !== null) {
        } else {
          await AsyncStorage.setItem(key, '1');
          if (auth().currentUser) {
            await auth().signOut();
          }
        }
      } catch (e) {
        console.log('=== HERE IS AN ERROR === ', e);
      }
    };

    clearUserOnFirstRun();

    setTimeout(() => {
      dispatch(login(navigation));
    }, 100);
  }, [dispatch, navigation]);
return ()
}

@storm2513
Copy link

I've added this code to App.js, so it's easily reproduced:

const run = async () => {
  const keys = await AsyncStorage.getAllKeys()
  console.log('KEYS', keys)
  const data = 'x'.repeat(1 * 1024 * 1024) + Math.random()
  AsyncStorage.setItem('test', JSON.stringify({ data }))
  AsyncStorage.setItem('test2', JSON.stringify({ data }))
}

setInterval(() => {
  run()
}, 100)

Quickly closing the app with back button and re-opening it on Android 9 immediately leads to error.

Here is the actual error that is visible in logs before facing with Cannot perform this operation because there is no current transaction.

E/SQLiteLog: (5) database is locked
2022-06-16 15:28:55.715 8918-9012/app E/SQLiteDatabase: Failed to open database '/data/user/0/app/databases/RKStorage'.
    android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5 SQLITE_BUSY[5]): , while compiling: PRAGMA journal_mode
        at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
        at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1229)
        at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:842)
        at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:490)
        at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:460)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:296)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
        at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:705)
        at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:272)
        at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:239)
        at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:1292)
        at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:1247)
        at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:903)
        at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:893)
        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:355)
        at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:298)
        at com.reactnativecommunity.asyncstorage.ReactDatabaseSupplier.ensureDatabase(ReactDatabaseSupplier.java:86)
        at com.reactnativecommunity.asyncstorage.ReactDatabaseSupplier.get(ReactDatabaseSupplier.java:112)
        at com.reactnativecommunity.asyncstorage.AsyncStorageModule$2.doInBackgroundGuarded(AsyncStorageModule.java:224)
        at com.reactnativecommunity.asyncstorage.AsyncStorageModule$2.doInBackgroundGuarded(AsyncStorageModule.java:192)
        at com.facebook.react.bridge.GuardedAsyncTask.doInBackground(GuardedAsyncTask.java:36)
        at com.facebook.react.bridge.GuardedAsyncTask.doInBackground(GuardedAsyncTask.java:20)
        at android.os.AsyncTask$2.call(AsyncTask.java:333)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at com.reactnativecommunity.asyncstorage.SerialExecutor$1.run(SerialExecutor.java:25)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)

@Wittiest
Copy link

@krizzu Any thoughts on post from @storm2513 above?

@github-actions
Copy link

This issue has been marked as stale due to inactivity. Please respond or otherwise resolve the issue within 7 days or it will be closed.

@github-actions github-actions bot added the Stale label Aug 24, 2022
@storm2513
Copy link

unstale

@tido64 tido64 added help wanted :octocat: need info Need more information from the author and removed Stale labels Aug 24, 2022
@Wittiest
Copy link

@tido64 Is the need info tag correct when there is a reproducible bug report?

@haroon-cb
Copy link

Facing this issue as well, when this error occurs my token gets wiped out from async storage and app logs out, anyone facing this issue?

@krizzu
Copy link
Member

krizzu commented Nov 15, 2022

@storm2513 @Wittiest

This comes down to using SQLite in a proper manner. The Resulting SQLITE_BUSY error comes from the fact that you're trying to write something to the database, while there's already a large write (or read) in progress. (SQLite docs)

const run = async () => {
  const keys = await AsyncStorage.getAllKeys()
  console.log('KEYS', keys)
  const data = 'x'.repeat(1 * 1024 * 1024) + Math.random()
  AsyncStorage.setItem('test', JSON.stringify({ data }))
  AsyncStorage.setItem('test2', JSON.stringify({ data }))
}

setInterval(() => {
  run()
}, 100)

With that code on app launch + kill/restart app like that will get you errors.

The original error was about trying to access the database, while the connection was already closed. DB connection is closed when Host tells AsyncStorage that it's about to be destroyed (not 100% but that might include not only app kill but also activity recreation).

This has been fixed in next storage because we keep the connection open as long as the app lives.

Facing this issue as well, when this error occurs my token gets wiped out from async storage and app logs out, anyone facing this issue?

@haroon-cb hey, you'll have to be a bit more specific - would be perfect to get a repo when issue can be reproduced 🙏

@haroon-cb
Copy link

We are unable to reproduce the issue, what we are doing is that we are storing our auth token in async-storage. We are using redux-persist to persist data in async storage. When we do an interaction that writes the data in redux-persist we get this error and app restarts and the token gets removed from async storage and thus the user logs out. We are using realm as a database and redux-persist as persistence layer.

Is this issue same as faced above by @ball-hayden?

P.s: We are not using next storage implementation yet.

The versions we are using:
async-storage: 1.15.14
redux-persist: 6.0.0
react-native: 0.66
realm: 10.20.0-beta.5
@krizzu

@ball-hayden
Copy link
Author

Very similar I think @haroon-cb - we're using apollo-cache-persist with this package as a backend.

@krizzu
Copy link
Member

krizzu commented Nov 15, 2022

@haroon-cb I'd still need more info to find what's happening.

what we are doing is that we are storing our auth token in async-storage. We are using redux-persist to persist data in async storage.

You're using AsyncStorage directly + letting redux-persist do its thing? If that's the case, maybe you use same keys, so they're being wiped out?

When we do an interaction that writes the data in redux-persist we get this error

so issue happens anytime you send an action?

@ball-hayden
apollo triggers saves on going to background, which might be causing the issue I mentioned above. Have you tried going with next storage, where we don't close DB connection on host destroy?

@haroon-cb
Copy link

haroon-cb commented Nov 15, 2022

We are using Async Storage directly to store the token and then using redux persist to store the application data that we want to persist. I don't think so that's there is issue due to same keys.

Yes it happens anytime we send an action. But it happens randomly, we were only able to reproduce it once. It's been months this issue is occuring, but no solution found. @krizzu

@ball-hayden
Copy link
Author

I haven't been able to try next storage @krizzu - sorry. It is on our backlog.

@krizzu
Copy link
Member

krizzu commented Nov 17, 2022

@haroon-cb That'd require a bit more investigation then. I don't know your setup and I don't want to shoot blanks here, so if you could provide more info, I might be of help.

@haroon-cb
Copy link

We have decided to implement next storage, will update if this issue resolves after using the next storage implementation.
If we don't add AsyncStorage_kotlinVersion and AsyncStorage_next_roomVersion to gradle.properties then default versions will be used? @krizzu

@MarySnopok
Copy link

We're experiencing same issue and applied next storage as it was suggested above. This change had lead to a noticeable spike in errors number on app start: Error: Unexpected AsyncStorage error: Failed resolution of: Landroidx/sqlite/util/ProcessLock; .
Similar to the above reporters we aren't able to reproduce the initial issue and only getting substantial number of reports from Sentry.

@krizzu
Copy link
Member

krizzu commented Mar 5, 2024

@MarySnopok Seems like you run into linkage error. From a small research I conducted just now, class ProcessLock was added in version 2.3.0 of sqlite-framework. The sqlite-framework used by Room 2.4.3 (default to AsyncStorage as for now) is at 2.2.0.

You can confirm that by running ./gradlew app:dependencies inside your android dir (standard RN project). Look for sqlite-framework dependency.

You can try to bump Room version, as described in docs here., to 2.5.0, which includes sqlite-framework as of 2.3.0. I haven't tested that version yet, so no guarantees.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted :octocat: need info Need more information from the author
Projects
None yet
Development

No branches or pull requests

8 participants