【发布时间】:2021-01-05 23:28:50
【问题描述】:
我的团队目前在跨所有平台(Android、iOS 和 UWP)的 Xamarin.Forms 应用程序中遇到问题。 Realm 经常会变得无响应,再次使用它的唯一方法是关闭应用程序。在过去的几个月里,它变得更加频繁和容易重现,但我们无法确定原因或解决方法。
我们已经确定了一些可能有助于确定正在发生的事情的模式。我们注意到,每当需要数据库中的信息时,我们都会看到工作线程卡在Realm.Write() 调用上。这种行为似乎几乎就像在 Realm 系统中发生了死锁一样。关于它被卡在哪个Write() 调用上并不一致,这似乎是基于领域何时失败的随机性。此时,任何其他通过任何方法访问此领域的尝试,例如Find()、All()、Remove() 等也会卡住。我们还确认 Write() 中的代码此时从未运行过,因为我们可以在第一行放置一个独立于领域的日志记录调用,并且永远不会在我们的日志中看到它。
一旦出现此问题,除此之外可能还会出现其他一些问题。我们的应用程序中还有另外两个领域,它们处理完全独立的数据,因此没有重叠的代码。这些 Realm 从来都不是这个问题的原因,但是当问题 Realm 卡住时,有时会导致其他 Realm 在下一次调用时也卡住。这个问题有时也会在应用程序的使用之间持续存在,导致第一次调用 Realm 时卡住,需要完全重新安装才能修复。
由于我们的应用程序使用基于反应式的编程,我们不得不以稍微不同的方式来构建我们处理数据库的方式。对于 Realm 问题,我们有一个服务,它可以在可观察的流中保持单个实例处于活动状态,然后可以订阅该实例以观察变化。我在这篇文章的末尾添加了一些这种架构的例子。我们还通过此流路由所有其他不可观察的操作,但是在调试期间,我们能够将这些调用移动到它们自己的独立领域实例,而几乎没有问题/功能没有变化。
目前,我们认为这很可能与我们如何将 Realm 转换为可观察系统有关,或者与我们的 Realms 以某种方式崩溃/损坏有关。
RealmStream 声明:
_realmStream = Observable
.Start(() => Realm.GetInstance(_dbConfig), _scheduler)
.Do(_ => logger.LogTrace("Realm created"), () => logger.LogTrace("Realm stream completed"))
.Replay()
.AutoConnect();
RealmStream 使用示例:
public IObservable<IChangeSet<TResult>> GetChangeSetStream<TSource, TResult>(Func<Realm, IQueryable<TSource>> selector, Func<TSource, TResult> transformFactory) where TSource : RealmObject
{
return _realmStream
.Select(realm =>
selector(realm)
.AsRealmCollection()
.ToObservableChangeSet<IRealmCollection<TSource>, TSource>()
.SubscribeOn(_scheduler)
.Transform(transformFactory)
.DisposeMany())
.Switch()
.Catch<IChangeSet<TResult>, Exception>(ex =>
{
_logger.LogError(ex, "Error getting property change stream");
return Observable.Return<IChangeSet<TResult>>(default);
})
.SubscribeOn(_scheduler);
}
Non-Observable 领域方法:
public async Task Run(Action<Realm> action)
{
await _realmStream
.Do(action)
.SubscribeOn(_scheduler);
}
public async Task<TResult> Run<TResult>(Func<Realm, TResult> action)
{
return await _realmStream
.Select(action)
.SubscribeOn(_scheduler);
}
到目前为止,我们已经尝试了以下方法:
- 确保 Realm 和 Xamarin 都在最新版本上
- 减少
Realm.Write()s 的数量(小改进) - 将每个 Realm 函数移动到我们的可观察系统中(没有明显变化,我们的大多数函数已经这样做了)
- 尝试将不需要可观察对象的所有内容移动到使用独立领域实例(增加锁定频率)
- 试图将所有内容从我们的单个 Realm 实例中移走。我们无法做到这一点,因为我们无法确定如何正确处理一些可观察的事件,例如 RealmObject 被删除,而不会导致严重的性能问题
【问题讨论】:
标签: xamarin xamarin.forms realm reactive-programming