当设备连接到网络时,AWS AppSync 离线突变会多次更新到服务器

Posted

技术标签:

【中文标题】当设备连接到网络时,AWS AppSync 离线突变会多次更新到服务器【英文标题】:AWS AppSync Offline mutations are getting updated to the server multiple times when the device is connected to the network 【发布时间】:2020-02-23 11:43:04 【问题描述】:

我在我的项目中使用 AWS AppSync android SDK,我注意到一个问题,当我运行突变时,如果设备连接到网络,它工作正常,但如果我进行离线突变然后启用我的网络,相同的突变被多次更新到服务器。所以我的数据库中有很多重复的条目。

尝试了不同的场景,但一旦建立网络连接,离线更新就会被调用两次或三次。

//AppSyncClient配置类

类客户端工厂

companion object 
    @Volatile
    private var mAWSAppSyncClient: AWSAppSyncClient? = null        
    private var cacheKeyResolver: CacheKeyResolver? = null
    private var appSyncSqlHelper: AppSyncSqlHelper?=null
    private var mNormalizedCacheFactory: SqlNormalizedCacheFactory?=null
    var  client:OkHttpClient?=null

    private lateinit var interceptor: HttpLoggingInterceptor
    @Synchronized
    fun getInstance(context: Context,utoken:String, dbName:String): AWSAppSyncClient? 
        if (cacheKeyResolver == null)
            cacheKeyResolver = object : CacheKeyResolver() 
                override fun fromFieldRecordSet(field: ResponseField, recordSet: Map<String, Any>): CacheKey 
                    val typeName = recordSet["__typename"] as String
                    if ("MessagesResponse" == typeName) 
                        val userKey = typeName + "." + recordSet["login"]
                        return CacheKey.from(userKey)
                    
                    if (recordSet.containsKey("id")) 
                        val typeNameAndIDKey = recordSet["__typename"].toString() + "." + recordSet["id"]
                        return CacheKey.from(typeNameAndIDKey)
                    
                    return CacheKey.NO_KEY
                

                override fun fromFieldArguments(field: ResponseField, variables: Operation.Variables): CacheKey 
                    return CacheKey.NO_KEY
                
            
    

        interceptor = HttpLoggingInterceptor()
        interceptor.level = HttpLoggingInterceptor.Level.BODY
        appSyncSqlHelper = AppSyncSqlHelper.create(context, dbName)
        mNormalizedCacheFactory =  SqlNormalizedCacheFactory(appSyncSqlHelper)

        if(client==null) 
            val cacheSize = 10 * 1024 * 1024 // 10MB
            client =
                OkHttpClient.Builder().cache(Cache(context.cacheDir, cacheSize.toLong())).addInterceptor(interceptor)
                    .addNetworkInterceptor  chain ->
                        val newRequest = chain.request().newBuilder()
                            .addHeader("Authorization", "Bearer ".plus(utoken))
                            .build()
                        chain.proceed(newRequest)
                    .build()
        

        val awsConfig = AWSConfiguration(context)
            mAWSAppSyncClient = AWSAppSyncClient.builder()
                .context(context)
                .okHttpClient(client)
                .normalizedCache(mNormalizedCacheFactory)
                .resolver(cacheKeyResolver)
                .persistentMutationsCallback(object : PersistentMutationsCallback 
                    override fun onFailure(error: PersistentMutationsError?)
                    
                        Log.v("dd","ff")
                    
                    override fun onResponse(response: PersistentMutationsResponse?)
                    
                        Log.v("dd","ff")
                    
                )
                .awsConfiguration(awsConfig)
                .build()
        return mAWSAppSyncClient
           

// 变异实现

        val graphqlCallback = object : GraphQLCall.Callback<MessageActivityMutation.Data>() 
            override fun onResponse(response: Response<MessageActivityMutation.Data>) 
                if(response!=null)                        
            
            override fun onFailure(e: ApolloException) 
                e.printStackTrace()                   
            
        
        ClientFactory.getInstance(thiscontext!!,preferencesHelper!!.userAuthToken,"messageackmutation_db")
            ?.mutate(MessageActivityMutation.builder()
            .id(msg_id)
            .verb(Constants.MESSAGE_ACKNOWLEDGED)
            .actioned_at(timeStamp)
            .build())
            ?.enqueue(graphqlCallback)

LOGCAT 详细信息***

2019-10-25 17:57:35.180 5403-8062/com.envoyer.app D/AppSyncOfflineMutationManager:线程:[23616]:互联网已断开。 2019-10-25 17:57:35.196 5403-5403/com.envoyer.app I/timberLog: Info-->Plain or R&AK with attachments 2019-10-25 17:57:35.218 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:在构造函数中 2019-10-25 17:57:35.218 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:启动泵 - 从持久存储中获取所有排队的突变 2019-10-25 17:57:35.218 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:从持久存储中获取所有突变请求 2019-10-25 17:57:35.220 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:退出构造函数。持久队列中有 [0] 个突变 2019-10-25 17:57:35.225 5403-5403/com.envoyer.app V/AppSyncComplexObjectsInterceptor:线程:[2]:实例化复杂对象拦截器 2019-10-25 17:57:35.235 5403-5403/com.envoyer.app V/AppSyncOfflineMutationInterceptor:线程:[2]:处理突变。 2019-10-25 17:57:35.235 5403-5403/com.envoyer.app V/AppSyncOfflineMutationInterceptor: Thread:[2]: 首先检查是否是重试突变遇到了冲突。 2019-10-25 17:57:35.235 5403-5403/com.envoyer.app V/AppSyncOfflineMutationInterceptor:线程:[2]:不,没有遇到冲突 2019-10-25 17:57:35.237 5403-5403/com.envoyer.app V/AppSyncOfflineMutationManager: 线程:[2]: 将突变 [7ce851b7-fb8e-4ec2-ac49-4b603ca13acd] 添加到内存队列 2019-10-25 17:57:35.237 5403-5403/com.envoyer.app V/S3ObjectManagerImplementation:线程:[2]:查看 [Integer] 类型的键 [id] 2019-10-25 17:57:35.239 5403-5403/com.envoyer.app V/S3ObjectManagerImplementation:线程:[2]:查看 [字符串] 类型的键 [动词] 2019-10-25 17:57:35.242 5403-5403/com.envoyer.app V/S3ObjectManagerImplementation:线程:[2]:查看 [String] 类型的键 [actioned_at] 2019-10-25 17:57:35.247 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:addPersistentMutationObject:添加突变[7ce851b7-fb8e-4ec2-ac49-4b603ca13acd]:MessageActivityMutation "query":"mutation MessageActivity($id: Int, $verb: String, $actioned_at: String)  MessageActivity(id: $id, verb: $verb, actioned_at: $actioned_at)   __typename  状态  数据  消息 ” ,"变量":"id":1833,"verb":"message.seen","actioned_at":"2019-10-25 12:27:35" 2019-10-25 17:57:35.263 5403-5403/com.envoyer.app V/AppSyncOfflineMutationManager:线程:[2]:将突变 [7ce851b7-fb8e-4ec2-ac49-4b603ca13acd] 添加到持久队列。未找到 S3 对象 2019-10-25 17:57:35.263 5403-5403/com.envoyer.app V/AppSyncOfflineMutationManager:线程:[2]:创建内存和持久记录。现在要向队列处理程序发出信号。 2019-10-25 17:57:35.263 5403-8068/com.envoyer.app V/QueueUpdateHandler: 线程:[23622]: 收到消息以对突变队列采取行动。 2019-10-25 17:57:35.263 5403-8068/com.envoyer.app V/QueueUpdateHandler:线程:[23622]:如果存在下一个突变,则收到处理下一个突变的消息。 2019-10-25 17:57:35.264 5403-8068/com.envoyer.app V/AppSyncOfflineMutationManager:线程:[23622]:互联网不可用。退出 2019-10-25 17:57:35.281 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager: 线程:[2]:In Constructor 2019-10-25 17:57:35.281 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:启动泵 - 从持久存储中获取所有排队的突变 2019-10-25 17:57:35.281 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:从持久存储中获取所有突变请求 2019-10-25 17:57:35.283 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:退出构造函数。持久队列中有 [1] 个突变 2019-10-25 17:57:35.288 5403-5403/com.envoyer.app V/AppSyncComplexObjectsInterceptor:线程:[2]:实例化复杂对象拦截器 2019-10-25 17:57:35.331 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager: 线程:[2]:In Constructor 2019-10-25 17:57:35.331 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:启动泵 - 从持久存储中获取所有排队的突变 2019-10-25 17:57:35.331 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:从持久存储中获取所有突变请求 2019-10-25 17:57:35.333 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:退出构造函数。持久队列中有 [1] 个突变 2019-10-25 17:57:35.337 5403-5403/com.envoyer.app V/AppSyncComplexObjectsInterceptor:线程:[2]:实例化复杂对象拦截器 2019-10-25 17:57:35.357 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager: 线程:[2]:In Constructor 2019-10-25 17:57:35.358 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:启动泵 - 从持久存储中获取所有排队的突变 2019-10-25 17:57:35.358 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:从持久存储中获取所有突变请求 2019-10-25 17:57:35.360 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:退出构造函数。持久队列中有 [1] 个突变 2019-10-25 17:57:35.368 5403-5403/com.envoyer.app V/AppSyncComplexObjectsInterceptor:线程:[2]:实例化复杂对象拦截器 2019-10-25 17:57:35.415 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:在构造函数中 2019-10-25 17:57:35.415 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:启动泵 - 从持久存储中获取所有排队的突变 2019-10-25 17:57:35.415 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:从持久存储中获取所有突变请求 2019-10-25 17:57:35.417 5403-5403/com.envoyer.app V/PersistentOfflineMutationManager:线程:[2]:退出构造函数。持久队列中有 [1] 个突变 2019-10-25 17:57:35.422 5403-5403/com.envoyer.app V/AppSyncComplexObjectsInterceptor:线程:[2]:实例化复杂对象拦截器 2019-10-25 17:57:35.470 5403-8067/com.envoyer.app D/AppSyncOfflineMutationManager:线程:[23621]:互联网断开。 2019-10-25 17:57:35.472 5403-8069/com.envoyer.app D/AppSyncOfflineMutationManager:线程:[23623]:互联网断开。 2019-10-25 17:57:35.472 5403-8071/com.envoyer.app D/AppSyncOfflineMutationManager:线程:[23625]:互联网断开。 2019-10-25 17:57:35.473 5403-8077/com.envoyer.app D/AppSyncOfflineMutationManager:线程:[23628]:互联网断开。 2019-10-25 17:57:35.474 5403-8080/com.envoyer.app D/AppSyncOfflineMutationManager:线程:[23630]:互联网断开。 2019-10-25 17:57:36.103 5403-8054/com.envoyer.app E/timberLog: onError-->websocket 抛出异常 2019-10-25 17:57:37.759 5403-7658/com.envoyer.app V/AppSyncOfflineMutationInterceptor:线程:[23596]:处理突变

******启用网络后*******

https://4betrpovsffuhjxad5ouxlm6um.appsync-api.eu-west-1.amazonaws.com/graphql (1824ms) 2019-10-25 17:58:31.140 5403-8282/com.envoyer.app D/OkHttp: 内容类型: application/json;charset=UTF-8 2019-10-25 17:58:31.140 5403-8282/com.envoyer.app D/OkHttp: 内容长度: 100 2019-10-25 17:58:31.140 5403-8282/com.envoyer.app D/OkHttp:日期:2019 年 10 月 25 日星期五 12:29:19 GMT 2019-10-25 17:58:31.140 5403-8282/com.envoyer.app D/OkHttp: x-amzn-requestid: e351113d-b8b4-416c-855c-6c28c95f1a98 2019-10-25 17:58:31.140 5403-8282/com.envoyer.app D/OkHttp: x-cache: 来自云端的小姐 2019-10-25 17:58:31.140 5403-8282/com.envoyer.app D/OkHttp:通过:1.1 bae54c9df29d44a26d5e0fd3d2c61c9c.cloudfront.net (CloudFront) 2019-10-25 17:58:31.140 5403-8282/com.envoyer.app D/OkHttp: x-amz-cf-pop: MAA50-C1 2019-10-25 17:58:31.141 5403-8282/com.envoyer.app D/OkHttp: x-amz-cf-id: Pl8OYaRmtJxPinPXFbGwcnfgQxyGlWJo1LE0n9_oQprRKeULGsvkCw== 2019-10-25 17:58:31.141 5403-8282/com.envoyer.app D/OkHttp: "data":"MessageActivity":"__typename":"Response","status":true,"data ":"[]","消息":"成功" 2019-10-25 17:58:31.141 5403-8282/com.envoyer.app D/OkHttp: https://4betrpovsffuhjxad5ouxlm6um.appsync-api.eu-west-1.amazonaws.com/graphql (1900ms) 2019-10-25 17:58:31.271 5403-8298/com.envoyer.app D/OkHttp: 内容类型: application/json;charset=UTF-8 2019-10-25 17:58:31.272 5403-8298/com.envoyer.app D/OkHttp: 内容长度: 100 2019-10-25 17:58:31.272 5403-8298/com.envoyer.app D/OkHttp:日期:2019 年 10 月 25 日星期五 12:29:19 GMT 2019-10-25 17:58:31.272 5403-8298/com.envoyer.app D/OkHttp: x-amzn-requestid: d0289bd6-3e31-49a6-815f-a708a1fa2233 2019-10-25 17:58:31.272 5403-8298/com.envoyer.app D/OkHttp: x-cache: 来自云端的小姐 2019-10-25 17:58:31.272 5403-8298/com.envoyer.app D/OkHttp: via: 1.1 bae54c9df29d44a26d5e0fd3d2c61c9c.cloudfront.net (CloudFront) 2019-10-25 17:58:31.272 5403-8298/com.envoyer.app D/OkHttp: x-amz-cf-pop: MAA50-C1 2019-10-25 17:58:31.272 5403-8298/com.envoyer.app D/OkHttp: x-amz-cf-id: 7wqu5JSmQJFT9layGkgpXB1WNpx5qD0-ohHF6TNHbU2l8gcBBUs0AQ== 2019-10-25 17:58:31.274 5403-8298/com.envoyer.app D/OkHttp: "data":"MessageActivity":"__typename":"Response","status":true,"data ":"[]","消息":"成功" 2019-10-25 17:58:31.274 5403-8298/com.envoyer.app D/OkHttp: https://4betrpovsffuhjxad5ouxlm6um.appsync-api.eu-west-1.amazonaws.com/graphql (2007ms) 2019-10-25 17:58:31.408 5403-8307/com.envoyer.app D/OkHttp: 内容类型: application/json;charset=UTF-8 2019-10-25 17:58:31.408 5403-8307/com.envoyer.app D/OkHttp: 内容长度: 100 2019-10-25 17:58:31.408 5403-8307/com.envoyer.app D/OkHttp:日期:2019 年 10 月 25 日星期五 12:29:19 GMT 2019-10-25 17:58:31.408 5403-8307/com.envoyer.app D/OkHttp: x-amzn-requestid: 6a575625-f4fa-4209-ac5c-e47f88297910 2019-10-25 17:58:31.408 5403-8307/com.envoyer.app D/OkHttp: x-cache: 来自云端的小姐 2019-10-25 17:58:31.409 5403-8307/com.envoyer.app D/OkHttp:通过:1.1 bae54c9df29d44a26d5e0fd3d2c61c9c.cloudfront.net (CloudFront) 2019-10-25 17:58:31.409 5403-8307/com.envoyer.app D/OkHttp: x-amz-cf-pop: MAA50-C1 2019-10-25 17:58:31.409 5403-8307/com.envoyer.app D/OkHttp: x-amz-cf-id: 1RaLA8-nyDTGsreE4QmtMETeslLvw3PmnHHdMZqzTXsYSjg3Y3kVbQ== 2019-10-25 17:58:31.411 5403-8307/com.envoyer.app D/OkHttp: "data":"MessageActivity":"__typename":"Response","status":true,"data ":"[]","消息":"成功" 2019-10-25 17:58:31.411 5403-8307/com.envoyer.app D/OkHttp: https://4betrpovsffuhjxad5ouxlm6um.appsync-api.eu-west-1.amazonaws.com/graphql (2152ms) 2019-10-25 17:58:31.469 5403-8281/com.envoyer.app D/OkHttp: 内容类型: application/json;charset=UTF-8 2019-10-25 17:58:31.470 5403-8281/com.envoyer.app D/OkHttp: 内容长度: 100 2019-10-25 17:58:31.470 5403-8281/com.envoyer.app D/OkHttp: 日期: 2019 年 10 月 25 日星期五 12:29:19 GMT 2019-10-25 17:58:31.470 5403-8281/com.envoyer.app D/OkHttp: x-amzn-requestid: 509dfabd-008d-477b-8e0d-247c2db21ced 2019-10-25 17:58:31.470 5403-8281/com.envoyer.app D/OkHttp: x-cache: 来自云端的小姐 2019-10-25 17:58:31.470 5403-8281/com.envoyer.app D/OkHttp: via: 1.1 bae54c9df29d44a26d5e0fd3d2c61c9c.cloudfront.net (CloudFront) 2019-10-25 17:58:31.470 5403-8281/com.envoyer.app D/OkHttp: x-amz-cf-pop: MAA50-C1 2019-10-25 17:58:31.470 5403-8281/com.envoyer.app D/OkHttp: x-amz-cf-id: -rdF8loaCHAAmZN8-mRIp9EIYOPJ5ngimAwyisRkoLwXnU_VdrmNAw== 2019-10-25 17:58:31.471 5403-8281/com.envoyer.app D/OkHttp: "data":"MessageActivity":"__typename":"Response","status":true,"data ":"[]","消息":"成功" 2019-10-25 17:58:31.471 5403-8281/com.envoyer.app D/OkHttp: https://4betrpovsffuhjxad5ouxlm6um.appsync-api.eu-west-1.amazonaws.com/graphql (2182ms) 2019-10-25 17:58:31.509 5403-8283/com.envoyer.app D/OkHttp: 内容类型: application/json;charset=UTF-8 2019-10-25 17:58:31.509 5403-8283/com.envoyer.app D/OkHttp: 内容长度: 100 2019-10-25 17:58:31.509 5403-8283/com.envoyer.app D/OkHttp: 日期: 2019 年 10 月 25 日星期五 12:29:19 GMT 2019-10-25 17:58:31.509 5403-8283/com.envoyer.app D/OkHttp: x-amzn-requestid: be28bb94-2788-449d-bc6f-af722e77e6d0 2019-10-25 17:58:31.509 5403-8283/com.envoyer.app D/OkHttp: x-cache: 来自云端的小姐 2019-10-25 17:58:31.509 5403-8283/com.envoyer.app D/OkHttp:通过:1.1 bae54c9df29d44a26d5e0fd3d2c61c9c.cloudfront.net (CloudFront) 2019-10-25 17:58:31.509 5403-8283/com.envoyer.app D/OkHttp: x-amz-cf-pop: MAA50-C1 2019-10-25 17:58:31.509 5403-8283/com.envoyer.app D/OkHttp: x-amz-cf-id: edvrZI0GEB_1DDoikzUVcFjpwwyIGAXl9elEqbgk-_ShvoKsP86kuw== 2019-10-25 17:58:31.510 5403-8283/com.envoyer.app D/OkHttp: "data":"MessageActivity":"__typename":"Response","status":true,"data ":"[]","消息":"成功" 2019-10-25 17:58:31.511 5403-8283/com.envoyer.app D/OkHttp:

【问题讨论】:

【参考方案1】:

我想我找到了答案,但不确定为什么会这样。这是除了在您的突变中覆盖onFailureonSuccess 之外,您还需要覆盖另一种方法,即onStatusEvent 并清除突变队列。我相信它有时会被调用两次或三次,一次用于调度,一次用于网络。

override fun onStatusEvent(event: GraphQLCall.StatusEvent) 
                    super.onStatusEvent(event)
                    awsAppSyncClient.clearMutationQueue()
                

希望对你有帮助。

【讨论】:

Tallal Tasawar 试过这个,但同样的问题仍然存在。谢谢! 理想情况下,您应该在后端使用 ID 处理此倍数,后端应检查 ID 是否已存在,不应将其视为新记录。

以上是关于当设备连接到网络时,AWS AppSync 离线突变会多次更新到服务器的主要内容,如果未能解决你的问题,请参考以下文章

aws appsync 离线:收到错误未提供变量 ID

离线时无法建立与本地主机的连接

AWS AppSync 如何在我离线时判断是不是存在未完成的突变?

新设备上的 AWS Appsync 缓存未命中和 403 错误

是否可以使用 AWS AppSync 构建离线优先的移动应用程序?

如何使用订阅和 AWS AppSync 高效同步 Apollo 的缓存