Nozbe / WatermelonDB

🍉 Reactive & asynchronous database for powerful React and React Native apps ⚡️
https://watermelondb.dev
MIT License
10.44k stars 587 forks source link

The action you're trying to perform (unnamed) can't be performed yet #203

Closed ptdede closed 5 years ago

ptdede commented 5 years ago

Hi! I Just discover this project and it's amazing! 🥇

I have several question about implementation to my project. So, I have function like this:

export async function asyncSaveOfflineDb (...) {
  // get watermelon database name from Repo databaseName
  // use it for db transaction
  const dbConv = getDatabaseName(databaseName)
  if (dbConv) {
    // get collection based on dbName
    const collection = database.collections.get(dbConv)

    try {
      // do watermelon database action
      await database.action(async () => {
        // Get data from DB. If no data saved yet, willUpdateData will be empty / null.
        const willUpdateData = await collection.query(
          Q.where('id', '' + rawData.id)
        ).fetch()

        // if willUpdateData is null, means data not in local DB
        // So create new DB based on raw data.
        if (!willUpdateData || willUpdateData.length === 0) {
          const newData = await collection.create(data => {
            // this allow us to passing data instead off declaring variable one by one.
            // pass all data to selectNormalize function,
            // and function will return data that suitable with the schema.
            data._raw = sanitizedRaw(selectNormalize(..., rawData), collection.schema)
          })
          console.log('CREATED data', newData, rawData)
        } else {
          // if willUpdateData is not empty, UPDATE THE DATA
          await willUpdateData[0].update(data => {
            data._raw = sanitizedRaw(selectNormalize(..., rawData), collection.schema)
          })
          console.log('UPDATED Data', willUpdateData, rawData)
        }
      })
    } catch (err) {
      console.log('ERORR UPDATE DATA', err, rawData)
      throw err
    }
  } else {
    console.log('DB not found or registered', databaseName)
  }
}

After several time trying, i got this warning message:

screen shot 2019-01-11 at 15 23 37

And when i build release for iOS, my app will stuck (not responding). Is this related with the warning?

Here is the first line error trace:

2019-01-11 15:27:24.265631+0800 rn_travlr[659:31471] Task <C86AB59B-8B96-4F93-8116-0910C3CCE8C3>.<57> finished with error - code: -999
2019-01-11 15:27:25.381613+0800 rn_travlr[659:31471] -[__NSCFNumber length]: unrecognized selector sent to instance 0xb0001683bcef4c53
2019-01-11 15:27:25.383 [fatal][tid:com.facebook.react.AsyncLocalStorageQueue] Exception '-[__NSCFNumber length]: unrecognized selector sent to instance 0xb0001683bcef4c53' was thrown while invoking multiSet on target AsyncLocalStorage with params (
        (
                (
            lastSync,
            1547191645381
        )
    ),
    24003
)

Also, I have a question about multithreading. Is it multithreaded in React Native? Thanks!

radex commented 5 years ago

And when i build release for iOS, my app will stuck (not responding). Is this related with the warning?

It is. The warning explains why the app appears stuck. Take a look at the docs: https://github.com/Nozbe/WatermelonDB/blob/master/docs/Actions.md

Also, I have a question about multithreading. Is it multithreaded in React Native? Thanks!

Yes. Native database code runs in a separate thread from JS thread and main thread.

ptdede commented 5 years ago

Yes. Native database code runs in a separate thread from JS thread and main thread.

Very cool!

It is. The warning explains why the app appears stuck. Take a look at the docs: https://github.com/Nozbe/WatermelonDB/blob/master/docs/Actions.md

Yes, i saw the docs. So, i have to use action in model instead using it from exported watermelon database?

radex commented 5 years ago

Yes, i saw the docs. So, i have to use action in model instead using it from exported watermelon database?

you can do database.action. The problem is that you have competing actions. You have some action running that has not completed (or errored out). You should see in console the body of the function that's running.

Either that or you're trying to run database.action from inside another action. In which case you need to use subAction API

Let me know if this makes sense to you.

ptdede commented 5 years ago

You should see in console the body of the function that's running.

Yep, so the function that causing this error is database.action. I test it by transform the function into:

export async function asyncSaveOfflineDb (...) {
  await database.action(async action => {})
}

I am pretty sure that i'm not running database.action inside other action.

But, I run asyncSaveOfflineDb multiple time simultaneously. For example I have <DataFetcher thatFetch={url} />, and i render multiple <DataFetcher /> in a Class (one screen). That component also have functionality to save data into localDB (asyncSaveOfflineDb).

Is this the culprit? So, i can't use watermelon database object by that way(simultaneously)?

ptdede commented 5 years ago

Update: I found that omitting actionsEnabled: true is solving this problem 😕

export const database = new Database({
  adapter,
  modelClasses: registeredModel,
  actionsEnabled: true  // --> omit this
})
andrewlorenz commented 4 years ago

its hard to see how not enabling actions (assuming that actionsEnabled does indeed do what it says it does!) would fix a problem with performing an action. Its also apparently mandatory to set actionsEnabled when initialising the database connection, so I'm now struggling to resolve the same error as the OP