realm / realm-js

Realm is a mobile database: an alternative to SQLite & key-value stores
https://realm.io
Apache License 2.0
5.78k stars 575 forks source link

Realm Crash Electron Renderer Process #5142

Closed cristiano-linvix closed 1 year ago

cristiano-linvix commented 1 year ago

How frequently does the bug occur?

All the time

Description

Electron app crashes when reload window.

Sentry logs: https://sentry.io/share/issue/e579f95b8a0b44139fde6f703c5eccca/ https://sentry.io/share/issue/7c819948d9a745248effc7a023b6fedc/

Stacktrace & log output

SymInit: Symbol-SearchPath: '.;C:\Projetos\Desktop\JavaScript\Self Checkout V2;C:\Projetos\Desktop\JavaScript\Self Checkout V2\node_modules\electron\dist;C:\Windows;C:\Windows\system32;SRV*C:\websymbols*http://msdl.microsoft.com/download/symbols;', symOptions: 530, UserName: 'Cristiano'
OS-Version: 10.0.22000 () 0x100-0x1
C:\Projetos\Desktop\JavaScript\Self Checkout V2\node_modules\segfault-handler\src\StackWalker.cpp (923): StackWalker::ShowCallstack
C:\Projetos\Desktop\JavaScript\Self Checkout V2\node_modules\segfault-handler\src\segfault-handler.cpp (242): segfault_handler
00007FFC2455C49A (ntdll): (filename not available): RtlAreLongPathsEnabled
00007FFC245159A2 (ntdll): (filename not available): RtlRestoreContext
00007FFC24512E63 (ntdll): (filename not available): RtlRaiseException
00007FFC21C8428C (KERNELBASE): (filename not available): RaiseException
00007FFC240F3B40 (RPCRT4): (filename not available): RpcRaiseException
00007FFC240F3B04 (RPCRT4): (filename not available): RpcRaiseException
00007FFC240F3ADC (RPCRT4): (filename not available): I_RpcSendReceive
00007FFC240E6170 (RPCRT4): (filename not available): RpcAsyncGetCallStatus
00007FFC240A1DF7 (RPCRT4): (filename not available): NdrClientCall2
00007FFC2417D661 (RPCRT4): (filename not available): NdrClientCall3
00007FFC240A13D8 (RPCRT4): (filename not available): RpcAsyncCompleteCall
00007FFC205E3E94 (WINSTA): (filename not available): WinStationRegisterConsoleNotificationEx
00007FFC205E3C5D (WINSTA): (filename not available): WinStationRegisterConsoleNotificationEx
00007FFC205E3597 (WINSTA): (filename not available): WinStationUnRegisterSessionNotification
00007FFC240FC9AD (RPCRT4): (filename not available): NdrFixedArrayMarshall
00007FFC240FC83A (RPCRT4): (filename not available): NdrFixedArrayMarshall
00007FFC24106746 (RPCRT4): (filename not available): NdrGetSimpleTypeMemorySize
00007FFC241076BE (RPCRT4): (filename not available): RpcServerUnregisterIfEx
00007FFC24106AE3 (RPCRT4): (filename not available): NdrGetSimpleTypeMemorySize
00007FFC24106928 (RPCRT4): (filename not available): NdrGetSimpleTypeMemorySize
00007FFC24108020 (RPCRT4): (filename not available): RpcAsyncCancelCall
00007FFC205E2408 (WINSTA): (filename not available): WinStationUnRegisterSessionNotification
00007FFC205E2143 (WINSTA): (filename not available): WinStationGetCurrentSessionCapabilities
00007FFC205E20E2 (WINSTA): (filename not available): WinStationGetCurrentSessionCapabilities
00007FFC205E22EE (WINSTA): (filename not available): WinStationUnRegisterSessionNotification
00007FFC205E2211 (WINSTA): (filename not available): WinStationUnRegisterSessionNotification
00007FFC1D9A24C3 (WTSAPI32): (filename not available): WTSUnRegisterSessionNotification
00007FF7D805DCB9 (electron): (filename not available): uv_fs_poll_getpath
00007FF7D805DC1A (electron): (filename not available): uv_fs_poll_getpath
00007FF7D6F13625 (electron): (filename not available): uv_fs_get_result
00007FF7D6F13428 (electron): (filename not available): uv_fs_get_result
00007FF7D5CB17B6 (electron): (filename not available): v8::metrics::LongTaskStats::LongTaskStats
00007FF7D5CAD65F (electron): (filename not available): v8::metrics::LongTaskStats::LongTaskStats
00007FF7D5CAD72B (electron): (filename not available): v8::metrics::LongTaskStats::LongTaskStats
00007FF7D5A4AA5D (electron): (filename not available): cppgc::SourceLocation::SourceLocation
00007FF7D9632CD2 (electron): (filename not available): Cr_z_crc32_z
00007FFC23C45550 (KERNEL32): (filename not available): BaseThreadInitThunk
00007FFC244E485B (ntdll): (filename not available): RtlUserThreadStart

Can you reproduce the bug?

Yes, always

Reproduction Steps

Create a project with CRA (https://www.mongodb.com/docs/realm/sdk/node/integrations/electron-cra/).

Import in the rendering process the realm and configure the database and insert data.

In my case, I use Device Sync in the cloud.

Once connected to device sync, I press f5 or ctrl + r and the process fails.

Version

10.22.0

What SDK flavour are you using?

Atlas Device Sync

Are you using encryption?

No, not using encryption

Platform OS and version(s)

Win11

Build environment

{
    "name": "electron-project",
    "description": "project",
    "version": "1.0.0",
    "private": true,
    "author": {
      "name": "Cristiano Júnior da Cruz",
      "email": "cristiano@linvix.com.br",
      "url": "mailto://cristiano@linvix.com.br"
    },
    "homepage": "./",
    "main": "public/electron.js",
    "build": {
      "files": [
        "build/**/*",
        "node_modules/**/*"
      ],
      "directories": {
        "buildResources": "assets"
      },
      "nsis": {
        "runAfterFinish": false,
        "allowElevation": true,
        "include": "electron-builder-script.nsh"
      }
    },
    "dependencies": {
      "@craco/craco": "6.4.5",
      "@electron/remote": "2.0.8",
      "@sentry/electron": "4.1.0",
      "@sentry/integrations": "7.21.1",
      "@sentry/react": "7.21.1",
      "@sentry/tracing": "7.21.1",
      "@sentry/utils": "7.21.1",
      "axios": "1.1.3",
      "react": "18.2.0",
      "react-dom": "18.2.0",
      "react-router-dom": "6.4.3",
      "react-scripts": "4.0.3",
      "realm": "10.22.0"
    },
    "resolutions": {
      "react-scripts/**/react-error-overlay": "6.0.9"
    },
    "scripts": {
      "lint": "eslint ./src --ext .js,.jsx,.ts,.tsx",
      "lint:fix": "eslint ./src --ext .js,.jsx,.ts,.tsx --fix",
      "start": "craco start",
      "build": "craco build",
      "test": "craco test",
      "eject": "react-scripts eject",
      "electron-symbols": "node sentry-symbols.js",
      "postinstall": "electron-builder install-app-deps",
      "predistribute": "yarn build && node scripts/sentry.js",
      "distribute": "electron-builder -w"
    },
    "eslintConfig": {
      "extends": [
        "react-app",
        "react-app/jest"
      ]
    },
    "browserslist": {
      "production": [
        ">0.2%",
        "not dead",
        "not op_mini all"
      ],
      "development": [
        "last 1 chrome version",
        "last 1 firefox version",
        "last 1 safari version"
      ]
    },
    "devDependencies": {
      "@sentry/cli": "2.8.1",
      "@sentry/webpack-plugin": "1.19.0",
      "@types/node": "^16.18.3",
      "@types/react": "^18.0.25",
      "@types/react-dom": "^18.0.8",
      "@types/realm": "^1.13.0",
      "@types/styled-components": "^5.1.26",
      "@typescript-eslint/parser": "^5.42.1",
      "babel-eslint": "10.1.0",
      "electron": "21.3.1",
      "electron-builder": "23.6.0",
      "electron-devtools-installer": "3.2.0",
      "electron-download": "4.1.1",
      "prettier": "2.7.1"
    }
  }

Cocoapods version

No response

kneth commented 1 year ago

@cristiano-linvix I would like to know how you open the Realm? Are you aware that you should open the Realm in the render process with { sync: true } and not with a full sync configuration? See also https://github.com/mongodb-university/realm-electron-advanced-quickstart

cristiano-linvix commented 1 year ago

Hello @kneth, i have a service with this configs.

I use in my app getRealm() into another files.

import into another file


// REALM
import getRealm from "~/database";

const realm = await getRealm();


> src/database/index.tsx

import Realm from "realm";

export const RealmAppConfigs = { id: "xxxxxxxxxxx", timeout: 10000, };

export const RealmConfiguration = { schema: [ // schemas here ], schemaVersion: 28, };

window.RealmDatabaseInstance = null;

const getRealmUser = async () => { const RealmApp = new Realm.App(RealmAppConfigs);

if (RealmApp.currentUser) {
    return RealmApp.currentUser;
} else {
    const RealmCredentials = Realm.Credentials.serverApiKey("xxxxxxxxxxxxx");

    return await RealmApp.logIn(RealmCredentials);
}

};

export default async function getRealm() { // dados do usuário do realm const user = await getRealmUser();

// partition value
const partition_value = "partition_value_here";

if (window.RealmDatabaseInstance) {
    return window.RealmDatabaseInstance;
}

window.RealmDatabaseInstance = new Realm({
    ...RealmConfiguration,
    sync: { user: user, partitionValue: partition_value },
});

return window.RealmDatabaseInstance;

}

export async function getAsyncRealm() { // dados do usuário do realm const user = await getRealmUser();

// partition value
const partition_value = "partition_value_here";

// retorna a conexão do realm com await
window.RealmDatabaseInstance = await Realm.open({
    ...RealmConfiguration,
    sync: { user: user, partitionValue: partition_value },
});

return window.RealmDatabaseInstance;

}

export const closeRealm = () => { if (window.RealmDatabaseInstance) { if (window.RealmDatabaseInstance.isClosed === false) { window.RealmDatabaseInstance.close(); } } };

cristiano-linvix commented 1 year ago

Is this not the correct way to use it?

cristiano-linvix commented 1 year ago

I have a particularity, because I need the user to configure some things that generate the partition value, in an asynchronous function.

But these settings do not exist at the time of app.whenReady().then(async () => {});

This will happen only after going through the installation screen (where it informs the serial license).

Another thing is that when I open the app I force the server sync to locally using the getAsyncRealm function and wait for the system screens to load.

kneth commented 1 year ago

Your getRealm() and getAsyncRealm() should only be used in the main process, and for the render processes you will need to open the Realm with sync: true instead of sync: { user: user, partitionValue: partition_value }.

cristiano-linvix commented 1 year ago

How would I go about passing these partition value values there to the main process, since they depend on the rendering process configuration?

Another question, when I open the app, I force a synchronization of recent data from the server (with the getAsyncRealm() function), how would I do that by opening it in the main process?

For the sync, I used as a basis the documentation (https://www.mongodb.com/docs/realm-sdks/js/latest/Realm.html#.open) which says it forces a sync when used.

Open a Realm asynchronously with a promise. If the Realm is synced, it will be fully synchronized before it is available. In the case of query-based sync, config.schema is required. An exception will be thrown if config.schema is not defined.

kneth commented 1 year ago

We know that using sync: true is a workaround until Realm has full multiprocess support (includind encryption and device sync - and all operating systems).

You open your sync Realm on the main process with the full configuration (partition value, user, etc.), and on the render processes you open with sync: true. This will open the Realm file as it was local (no device sync) - and the main process will do all the syncing. So the render processes only need to know the path and not partition value and user.

cristiano-linvix commented 1 year ago

But, using it this way, if I use await Realm.open() does it force sync with the server?

kneth commented 1 year ago

await Realm.open() does it force sync with the server?

The behaviour can controlled by newRealmFileBehavior and existingRealmFileBehavior (see the sync configuration documentation for details).

rossicler-hostalky commented 1 year ago

We know that using sync: true is a workaround until Realm has full multiprocess support (includind encryption and device sync - and all operating systems).

You open your sync Realm on the main process with the full configuration (partition value, user, etc.), and on the render processes you open with sync: true. This will open the Realm file as it was local (no device sync) - and the main process will do all the syncing. So the render processes only need to know the path and not partition value and user.

Hi, I tried using that same config you mentioned, but when I try to create realm with new Realm({ ...config, sync: true }) inside the renderer process, it gives me the error below: Module not found: Error: Can't resolve 'react-native' in '/Users/.../app/node_modules/realm/lib' Did you mean './react-native'? Requests that should resolve in the current directory need to start with './'. Requests that start with a name are treated as module requests and resolve within module directories (node_modules). If changing the source code is not an option there is also a resolve options called 'preferRelative' which tries to resolve these kind of requests in the current directory too. .

Opening the realm connection inside main renderer works fine tho, I', only having problem inside the renderer