【企业微信】修复会话存档 SDK 每次 API 调用后被销毁并重新初始化的问题#3934
Conversation
Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com>
🤖 Augment PR Summary总结:本 PR 修复企业微信会话存档(MsgAudit)SDK 在每次 API 调用后被反复销毁并重新初始化的问题,通过引用计数 + 过期判断实现 SDK 复用。 主要变更:
技术要点:销毁动作由“最后一次释放”改为“最后一次释放且已过期”,而过期后的清理依旧会在后续重新初始化( 🤖 Was this summary useful? React with 👍 or 👎 |
| * 验证:多线程场景下,多个并发调用的引用计数正确性 | ||
| */ | ||
| @Test | ||
| public void testConcurrentRefCounting() throws Exception { |
| /** | ||
| * 减少会话存档SDK的引用计数 | ||
| * 当引用计数降为0时,自动销毁SDK以释放资源 | ||
| * 当引用计数降为0且SDK已过期时,才自动销毁SDK以释放资源 |
There was a problem hiding this comment.
Pull request overview
该 PR 修复企业微信会话存档(MsgAudit)SDK 在每次 API 调用结束时因引用计数归零而被无条件销毁、导致频繁重新初始化的问题,从而避免不必要的 SDK teardown/init 循环,提升调用效率并降低抖动。
Changes:
- 在
WxCpDefaultConfigImpl/WxCpRedisConfigImpl中,将DestroySdk的触发条件调整为“引用计数归零且 SDK 已过期”。 - 更新
WxCpConfigStorage中与引用计数/释放相关的 Javadoc,反映新的生命周期约定。 - 新增
WxCpDefaultConfigImplMsgAuditSdkTest并加入 TestNG suite,覆盖“未过期时不销毁、可复用”等场景。
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImpl.java | 引用计数归零时仅在 SDK 过期场景才销毁,避免每次调用都 destroy/init |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpRedisConfigImpl.java | 同步修复 Redis 配置实现中的销毁条件,保持行为一致 |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java | 更新接口文档以匹配新的生命周期与返回值语义 |
| weixin-java-cp/src/test/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImplMsgAuditSdkTest.java | 新增单测验证 SDK 在未过期且 refCount 归零时不会被销毁、可被复用 |
| weixin-java-cp/src/test/resources/testng.xml | 将新增测试类纳入 TestNG 执行列表 |
| * | ||
| * @param sdk sdk id | ||
| * @return 减少后的引用计数,如果返回0表示SDK已被销毁,如果SDK不匹配返回-1 | ||
| * @return 减少后的引用计数,如果SDK不匹配返回-1 |
| /** | ||
| * 验证:多线程场景下,多个并发调用的引用计数正确性 | ||
| */ | ||
| @Test | ||
| public void testConcurrentRefCounting() throws Exception { | ||
| long fakeSdk = 77777L; | ||
| setField("msgAuditSdk", fakeSdk); | ||
| setField("msgAuditSdkExpiresTime", System.currentTimeMillis() + VALID_EXPIRATION_TIME_OFFSET); | ||
| setField("msgAuditSdkRefCount", 0); | ||
|
|
||
| // 模拟 3 个并发调用同时持有 SDK | ||
| long sdk1 = config.acquireMsgAuditSdk(); | ||
| long sdk2 = config.acquireMsgAuditSdk(); | ||
| long sdk3 = config.acquireMsgAuditSdk(); | ||
|
|
||
| Assert.assertEquals(sdk1, fakeSdk); | ||
| Assert.assertEquals(sdk2, fakeSdk); | ||
| Assert.assertEquals(sdk3, fakeSdk); | ||
| Assert.assertEquals((int) getField("msgAuditSdkRefCount"), 3, "应有 3 个引用"); | ||
|
|
||
| // 逐一释放 | ||
| config.releaseMsgAuditSdk(fakeSdk); | ||
| Assert.assertEquals((int) getField("msgAuditSdkRefCount"), 2, "释放一个后应有 2 个引用"); | ||
| Assert.assertEquals((long) getField("msgAuditSdk"), fakeSdk, "SDK 仍有引用,不应被销毁"); | ||
|
|
||
| config.releaseMsgAuditSdk(fakeSdk); | ||
| Assert.assertEquals((int) getField("msgAuditSdkRefCount"), 1, "释放两个后应有 1 个引用"); | ||
|
|
||
| config.releaseMsgAuditSdk(fakeSdk); | ||
| Assert.assertEquals((int) getField("msgAuditSdkRefCount"), 0, "全部释放后引用计数应为 0"); | ||
| // SDK 未过期,不应被销毁 | ||
| Assert.assertEquals((long) getField("msgAuditSdk"), fakeSdk, "SDK 未过期,全部引用释放后不应被销毁"); | ||
| } |
| Assert.assertEquals(refCountAfterRelease, 0, "引用计数应为 0"); | ||
| } | ||
|
|
||
| /** |
|
@copilot 更新当前PR的标题和描述为中文,并解决合并冲突问题 |
|
@copilot apply changes based on the comments in this thread |
- 解决与 develop 分支的合并冲突(WxCpConfigStorage.java) - 合并 develop 中对引用计数接口方法增加的 @deprecated 标注 - 修正测试方法名:testConcurrentRefCounting → testMultipleAcquireAndReleaseSequential, 去除误导性的'并发'描述,改为准确的串行多次获取/释放验证 - 新增 testReleaseMsgAuditSdkShouldDestroyWhenExpired:验证 SDK 过期且 引用计数归零时,代码路径正确进入销毁分支(在无原生库的测试环境中 通过捕获 UnsatisfiedLinkError 证明 Finance.DestroySdk 被调用) - 完善 decrementMsgAuditSdkRefCount 的 @return Javadoc 描述 Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com>
已完成(commit
全部 9 个测试通过,checkstyle 检查无误。 |
Agent-Logs-Url: https://github.com/binarywang/WxJava/sessions/3b96b85a-8f3e-4bc0-b3ac-d5b9dd72744b Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com>
代码评审中的三项变更(Javadoc 本次另外同步了文档(commit
|
Agent-Logs-Url: https://github.com/binarywang/WxJava/sessions/3b96b85a-8f3e-4bc0-b3ac-d5b9dd72744b Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com>
releaseMsgAuditSdk/decrementMsgAuditSdkRefCount方法在引用计数归零时无条件调用Finance.DestroySdk(),与 SDK 是否已过期无关。由于每个高层方法(如getChatRecordPlainText)恰好获取并释放一个引用,导致每次 API 调用都触发完整的 SDK 销毁 + 重新初始化循环。根本原因
修复方案
仅当引用计数归零且 SDK 已过期时才销毁 SDK。SDK 有效期间保留缓存,供后续调用直接复用,无需重新初始化。
过期清理仍能自然触发:
acquireMsgAuditSdk()对已过期 SDK 返回 0,从而触发initSdk(),initSdk()调用updateMsgAuditSdk()在缓存新句柄前销毁旧句柄。变更内容
WxCpDefaultConfigImpl— 在releaseMsgAuditSdk和decrementMsgAuditSdkRefCount中均加入isMsgAuditSdkExpired()条件守卫WxCpRedisConfigImpl— 同上WxCpConfigStorage— 更新 Javadoc,反映正确的生命周期约定;完善decrementMsgAuditSdkRefCount的@return说明(SDK 不匹配或引用计数已为 0 时均返回 -1);合并 develop 分支中新增的@Deprecated标注WxCpDefaultConfigImplMsgAuditSdkTest— 新增单元测试,覆盖以下场景:testMultipleAcquireAndReleaseSequential)testReleaseMsgAuditSdkShouldDestroyWhenExpired,在无原生库的测试环境中通过捕获UnsatisfiedLinkError验证代码路径)Original prompt
📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.