You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Realm downloadAllServerChanges()挂起方法未同步变更问题及替代方案咨询

问题

使用verifyPaidStatus函数根据ID验证用户支付状态,通过while循环调用realm.syncSession.downloadAllServerChanges()同步Realm数据,直到状态变为Approved。但MongoDB端已更新数据,App端却无法实时获取到最新状态。

相关代码如下:

验证函数

suspend fun verifyPaidStatus(id: String): Boolean
    {
        var out = false
        while(!out)
        {
            realm.syncSession.downloadAllServerChanges()

            realm.write {
                val status =
                    realm.query<PaidStatus>("paidStatusId = $0", id).first().find()
                if (status != null) {
                    findLatest(status)!!.also {
                        if(it.paidStatusId == id && it.message == "Approved") {
                            out = true
                        }
                    }
                }
            }
            if(!out)
                delay(1000)
        }
        return out
    }

调用方式

val job = withTimeoutOrNull(10000)
 {
     verifyPaidStatus(invoiceId + restaurantMID)
 }

 if(job == null)
    somethingWrong = true

请问该问题原因是什么?是否有其他方式获取服务器最新变更,确认Atlas函数添加的数据是否同步成功?


问题原因分析

  • downloadAllServerChanges()的局限性:该方法仅同步当前已订阅的数据集合,若PaidStatus不在客户端订阅范围内,服务器端的更新无法被拉取。同时它是一次性同步操作,不会监听后续变更,若同步过程中出现网络波动、会话异常等情况,会导致同步失败但无反馈。
  • 写事务内查询的逻辑问题:在realm.write事务内执行查询并调用findLatest(status),事务内的Realm视图是事务启动时的快照,无法获取刚同步的最新数据,导致判断逻辑基于旧数据。
  • 未处理同步异常:代码未捕获downloadAllServerChanges()可能抛出的网络错误、会话断开等异常,一旦同步失败,循环只会持续等待,无法感知问题。

替代解决方案

1. 使用Realm变更监听机制(推荐)

直接监听目标PaidStatus对象的变更,无需轮询同步,实现实时响应:

suspend fun verifyPaidStatus(id: String): Boolean = suspendCancellableCoroutine { cont ->
    val query = realm.query<PaidStatus>("paidStatusId = $0", id)
    val job = query.asFlow().collectLatest { results ->
        results.firstOrNull()?.takeIf { it.message == "Approved" }?.let {
            cont.resume(true)
        }
    }
    cont.invokeOnCancellation {
        job.cancel()
    }
}

该方式会自动监听服务器端的变更,一旦目标对象状态变为Approved,立即返回结果,无需手动触发同步。

2. 修正手动同步与查询逻辑

若仍需手动同步,调整查询逻辑到读事务中,并处理同步异常:

suspend fun verifyPaidStatus(id: String): Boolean {
    var out = false
    while(!out) {
        try {
            realm.syncSession.downloadAllServerChanges()
            // 用读事务获取最新数据快照
            realm.read {
                val status = query<PaidStatus>("paidStatusId = $0", id).first().find()
                status?.let {
                    if (it.message == "Approved") out = true
                }
            }
        } catch (e: Exception) {
            // 处理同步或查询异常,比如网络错误
            e.printStackTrace()
        }
        if(!out) delay(1000)
    }
    return out
}

注意:需确保PaidStatus已被客户端订阅,可通过以下代码添加订阅:

realm.subscriptions.update {
    add(realm.query<PaidStatus>("paidStatusId = $0", id))
}

3. 检查Atlas端配置

  • 确认Atlas函数写入PaidStatus时已正确提交事务,且paidStatusId与客户端查询的ID完全匹配(注意拼接规则、大小写)。
  • 检查Atlas同步规则,确保客户端拥有该数据的读取权限。

内容的提问来源于stack exchange,提问作者dhaval123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 10:54:57