pubkey / rxdb

A fast, local first, reactive Database for JavaScript Applications https://rxdb.info/
https://rxdb.info/
Apache License 2.0
21.37k stars 1.04k forks source link

PrematureCommitError: Transaction committed too early on addCollections() #6008

Closed Mike-FR closed 3 months ago

Mike-FR commented 4 months ago

Hello,
I was using rxdb 14 on a Vue 2.7 project without problems. I updated rxdb to version 15 and since then I'm facing a PrematureCommitError" error when doing addCollections(). I tried several things without success so I redid a basic implementation on an internal test repository which runs on Vue 3. Same error. Here is the code on my test repo.

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import i18n from "./setup/i18n";
import createVuetify from "./setup/vuetify";
import SocioManifest from "../socio-manifest.json";
import PackageJson from "../package.json";
import SocioVueComponents, {
  initializeTracingAndLogging,
} from "@socotec.io/socio-vue-components";

import { addRxPlugin } from 'rxdb';
import { createRxDatabase } from 'rxdb';
import { getRxStorageDexie } from 'rxdb/plugins/storage-dexie';
import { RxDBDevModePlugin } from 'rxdb/plugins/dev-mode';

addRxPlugin(RxDBDevModePlugin);

initializeTracingAndLogging(SocioManifest, PackageJson, { router });

const createDatabase = async () => {
  const myDatabase = await createRxDatabase({
    name: 'mydatabase',
    storage: getRxStorageDexie()
  });

  const todoSchema = {
      version: 0,
      primaryKey: 'id',
      type: 'object',
      properties: {
          id: {
              type: 'string',
              maxLength: 100 // <- the primary key must have set maxLength
          },
          name: {
              type: 'string'
          },
          done: {
              type: 'boolean'
          },
          timestamp: {
              type: 'string',
              format: 'date-time'
          }
      },
      required: ['id', 'name', 'done', 'timestamp']
    }

    await myDatabase.addCollections({
      todos: {
        schema: todoSchema
      }
    });

    return {
      install(app) {
        app.provide(myDatabase);
      },
    };
  }

const db = createDatabase()

const app = createApp(App);

app.use(router);
app.use(store);
app.use(i18n);
app.use(createVuetify(i18n));
app.use(SocioVueComponents, i18n);

db.then(database => {
  app.use(database).mount('#app');
});

my package.json if it helps

{
  "name": "test-infra-front",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "serve": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore",
    "lint:fix": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --ignore-path .gitignore --fix",
    "format": "prettier --write . --ignore-path .gitignore"
  },
  "dependencies": {
    "@bufbuild/protobuf": "^1.7.2",
    "@connectrpc/connect": "^1.3.0",
    "@connectrpc/connect-web": "^1.3.0",
    "@intlify/unplugin-vue-i18n": "^2.0.0",
    "@socotec.io/socio-grpc-api": "^776.0.7",
    "@socotec.io/socio-vue-components": "vue3",
    "@vue/compat": "^3.4.16",
    "@vuex-orm/core": "^0.36.4",
    "axios": "^1.3.0",
    "core-js": "^3.35.0",
    "oidc-client": "^1.11.5",
    "rxdb": "^15.20.0",
    "rxjs": "^7.8.1",
    "vite-plugin-vuetify": "^2.0.1",
    "vue": "^3.3.11",
    "vue-i18n": "^9.8.0",
    "vue-router": "^4.2.5",
    "vuetify": "^3.4.10",
    "vuex": "^4.0.2",
    "vuex-oidc": "^3.10.1"
  },
  "devDependencies": {
    "@rushstack/eslint-patch": "^1.3.3",
    "@vitejs/plugin-vue": "^4.5.2",
    "@vue/eslint-config-prettier": "^8.0.0",
    "eslint": "^8.49.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-prettier": "^5.1.2",
    "eslint-plugin-vue": "^9.19.2",
    "eslint-plugin-vuetify": "^2.1.1",
    "lint-staged": "^15.2.0",
    "prettier": "^3.0.3",
    "sass": "^1.69.7",
    "terser": "^5.27.0",
    "vite": "^5.0.10",
    "yorkie": "^2.0.0"
  },
  "gitHooks": {
    "pre-commit": "lint-staged"
  },
  "lint-staged": {
    "*.{js,vue}": [
      "yarn lint",
      "yarn format",
      "git add ."
    ]
  }
}

The error inside the console that appears immediately
image

The IndexexDB look likes
image

Do you see an implementation error? Thanks for your help.

AMontagu commented 4 months ago

To add more informations while debugging (I am working with @Mike-FR )

The code that emit exception start here: https://github.com/pubkey/rxdb/blob/master/src/rx-database.ts#L351

The bulkWrite funciton is called first time with internal-add-storage-token and second time with rx-database-add-collection that is the one we are interested in.

The devMode is True.

The scopeFuncIsAsync is True.

The transaction code run without issue but when it try to commit it directly send to: https://github.com/dexie/Dexie.js/blob/a5519e58e407c518cb47c10673fc8c2fe585a389/src/classes/dexie/transaction-helpers.ts#L99

So IMO there is something between https://github.com/pubkey/rxdb/blob/master/src/plugins/storage-dexie/rx-storage-instance-dexie.ts#L148 and https://github.com/pubkey/rxdb/blob/master/src/plugins/storage-dexie/rx-storage-instance-dexie.ts#L202

that do not respect Dexie rule: https://dexie.org/docs/DexieErrors/Dexie.PrematureCommitError.html

AMontagu commented 4 months ago

By looking more the issue probably come from incrementExpectedAwaits or decrementExpectedAwaits. https://github.com/dexie/Dexie.js/blob/master/src/helpers/promise.js#L597 https://github.com/dexie/Dexie.js/blob/master/src/helpers/promise.js#L607

Meaning that we may have some other dependecy changing the default behavior of async/await. We will try to go with an empty vue/vite project. Then if not working an empty vanilla project.

Mike-FR commented 4 months ago

I identified that the problem comes from the zone.js package and in our case it is itself installed by @opentelemetry/context-zone itself installed by @grafana/faro-web-tracing that we use in our Vue frontend.

AMontagu commented 4 months ago

Look like: https://github.com/pubkey/rxdb/issues/6011

Is that mean we need to wait for faro to update dependencies of zone js ?

stale[bot] commented 4 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed soon. Please update it or it may be closed to keep our repository organized. The best way is to add some more information or make a pull request with a test case. Also you might get help in fixing it at the RxDB Community Chat If you know you will continue working on this, just write any message to the issue (like "ping") to remove the stale tag.

Mike-FR commented 4 months ago

ping

stale[bot] commented 4 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed soon. Please update it or it may be closed to keep our repository organized. The best way is to add some more information or make a pull request with a test case. Also you might get help in fixing it at the RxDB Community Chat If you know you will continue working on this, just write any message to the issue (like "ping") to remove the stale tag.

stale[bot] commented 3 months ago

Issues are autoclosed after some time. If you still have a problem, make a PR with a test case or to prove that you have tried to fix the problem.