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

Realm notifications inside write transaction #4701

Closed
TeunVR opened this issue Feb 27, 2017 · 10 comments
Closed

Realm notifications inside write transaction #4701

TeunVR opened this issue Feb 27, 2017 · 10 comments
Labels

Comments

@TeunVR
Copy link

TeunVR commented Feb 27, 2017

Goals

I want to be able to create new notifications when something has happend in the realm database (so when another notification fires).
In my case i use RxRealm to create Observables (which are just wrappers around the notification system).
Sometimes i need to have a global query (like which Team is the current team). And then when those query results are updated i need to make a new query (and notifications) because the current team was changed.
This mostly works, but not always when modifying the Realm database on a background queue. When going back to the mainqueue the realm will advance to the latest version when a new write-transaction is started. This causes the notifications to fire inside the write-transaction, triggering a crash: Terminating app due to uncaught exception 'RLMException', reason: 'Cannot create asynchronous query while in a write transaction'
I have attached a simple demo project.

Expected Results

I think the advance of the realm to the latest version should not trigger notifications until the write transaction is completed?

Two possible workarounds:

  • call realm.refresh() before starting write transaction
  • add .delay(0.0, scheduler: MainScheduler.instance) to Observables.

Actual Results

2017-02-27 12:21:06.482 RealmNotificationCrash[96253:19233708] *** Terminating app due to uncaught exception 'RLMException', reason: 'Cannot create asynchronous query while in a write transaction'
*** First throw call stack:
(
0 CoreFoundation 0x000000010a911d4b exceptionPreprocess + 171
1 libobjc.A.dylib 0x00000001081a621e objc_exception_throw + 48
2 Realm 0x0000000107013a88 -[RLMRealm beginWriteTransaction] + 136
3 RealmSwift 0x00000001077d950d TFC10RealmSwift5Realm10beginWritefT_T + 45
4 RealmSwift 0x00000001077d93f0 TFC10RealmSwift5Realm5writefzFzT_T_T + 48
5 RealmNotificationCrash 0x0000000106d0182b TFFFC22RealmNotificationCrash14ViewController19newTeamCrashClickedFP_T_U_FT_T_U0_FT_T + 123
6 RealmNotificationCrash 0x0000000106d00e37 TTRXFo___XFdCb
+ 39
7 libdispatch.dylib 0x000000010af1b978 _dispatch_call_block_and_release + 12
8 libdispatch.dylib 0x000000010af450cd _dispatch_client_callout + 8
9 libdispatch.dylib 0x000000010af258a4 _dispatch_main_queue_callback_4CF + 406
10 CoreFoundation 0x000000010a8d5e49 CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE + 9
11 CoreFoundation 0x000000010a89b37d __CFRunLoopRun + 2205
12 CoreFoundation 0x000000010a89a884 CFRunLoopRunSpecific + 420
13 GraphicsServices 0x00000001103e9a6f GSEventRunModal + 161
14 UIKit 0x0000000108675c68 UIApplicationMain + 159
15 RealmNotificationCrash 0x0000000106d040df main + 111
16 libdyld.dylib 0x000000010af9168d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Steps to Reproduce

See demo project.

Code Sample

See demo project.

Version of Realm and Tooling

  • Realm (2.4.3):
    • Realm/Headers (= 2.4.3)
  • Realm/Headers (2.4.3)
  • RealmSwift (2.4.3):
    • Realm (= 2.4.3)
  • RxRealm (0.5.1):
    • RealmSwift (~> 2.2)
    • RxSwift (~> 3.1)
  • RxSwift (3.2.0)

Xcode version: 8.2.1 (8C1002)

iOS/OSX version: 10

Dependency manager + version: Cocoapods 1.2.0

RealmNotificationCrash.zip

@pigeondotdev
Copy link

Hi @TeunVR. Thanks for reaching out about this. Someone will review what you've shared and follow-up with you soon. Cheers!

@austinzheng
Copy link
Contributor

Thanks for getting in touch with us. The behavior you're seeing is expected. Realm notifications may be delivered while Realm is in the middle of a write transaction, and it's not allowed to register a notification block while in the middle of a write transaction. You can check out our docs for more information.

@TeunVR
Copy link
Author

TeunVR commented Feb 28, 2017

Ah yes, is see. I missed this part in the docs:

If a Realm is advanced to the latest version as part of starting a write transaction, notification handlers might be called synchronously. This will happen if, when the Realm was advanced to the latest version, Realm entities being observed were modified or deleted in a way that would trigger notifications. Such notifications will run within the context of the current write transaction, meaning attempting to begin a write transaction within the notification handler will cause Realm to throw an exception.

I understand that it is expected behavior, but is it also wanted behavior? Just curious what the usecase is.

Is calling refresh() an expensive operation when the realm is already up-to-date? Otherwise i can add an extension that always calls refresh() before starting the write-transaction.

@austinzheng
Copy link
Contributor

We actually just added that part of the docs recently, so if you read the docs more than a week ago it might not have been there!

If you want to learn more about the rationale of why transactions work the way they do, you might want to skim through this thread. Basically, before a recent fix we made we were simply dropping notifications that were being delivered while in the middle of a write transaction.

I would not expect manually calling refresh() to impose a significant performance penalty, especially relative to the cost of beginning and committing a write transaction. You can try it, and in the unlikely event that you see performance problems run the profiler in Instruments to see if it really is refresh() causing issues.

Feel free to get back to us with any further questions you might have about Realm!

@TeunVR
Copy link
Author

TeunVR commented Feb 28, 2017

Ah that explains why i missed it :)
Thanks for the explanation, i will find a workaround.
Calling refresh() just before the write-transaction leaves a small gap in which another thread can still write to the realm. It will not solve this problem entirely, but it might be good-enough in combination with checking for ongoing write transaction.

@austinzheng
Copy link
Contributor

Thanks! If refresh() proves to be unsatisfactory or you have any other questions about Realm, feel free to open a new ticket.

@Double-Dude
Copy link

I have a scenario that Person owns and creates a Dog when Person gets created, if a Person gets added to Realm DB then I observe Dog as I want to know the change of Dog.

So I first observe Person collection, then if a Person get inserted, I immediately create observer to observe Dog(person.dog.observe), then the app crashes with message:
"Cannot register notification blocks from within write transactions."

I think realm.beginTransaction(person.insert()) triggers the personCollection.observe block then it calls dog.observe and that's why it has the message above. How should I observe a dog of a person when a person gets inserted/updated?

@duncangroenewald
Copy link

No answer ?

@bmunkholm
Copy link
Contributor

@duncangroenewald Please open new issues. We usually don't see & respond to comments on closed issues. Thanks!

@aehlke
Copy link

aehlke commented Dec 14, 2023

@Double-Dude did you resolve that?

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 14, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

8 participants