feat(t14-v1234): 消息迁移增强——C2C全量分页+群消息迁移+429限速重试+回溯天数可配
V1: migrateMessages 7天窗滚动 + Complete分页拉全量历史 V2: migrateGroupMessages + getGroupMsgAs/importGroupMsg + /migrate/groupmsg V3: importMsg/importGroupMsg 捕获429重试 + app.yml imutil.migrate(msgLookbackDays/importMaxRetry/importRetryMs) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package com.imutil.tencent;
|
||||
|
||||
import com.imutil.common.BizException;
|
||||
import com.imutil.common.Httpx;
|
||||
import com.imutil.common.Jsons;
|
||||
import com.imutil.common.LocalCache;
|
||||
@@ -60,6 +61,15 @@ public class TencentImClient {
|
||||
@Inject
|
||||
private RateLimiter rateLimiter;
|
||||
|
||||
// ===== 数据迁移:消息导入限速重试(T14 V3)=====
|
||||
/** 消息导入 429 限流重试次数 */
|
||||
@Inject("${imutil.migrate.importMaxRetry:3}")
|
||||
private int migrateImportMaxRetry;
|
||||
|
||||
/** 消息导入重试间隔(毫秒) */
|
||||
@Inject("${imutil.migrate.importRetryMs:1000}")
|
||||
private long migrateImportRetryMs;
|
||||
|
||||
@Inject
|
||||
private TenantService tenantService;
|
||||
|
||||
@@ -283,6 +293,38 @@ public class TencentImClient {
|
||||
return callApi("group_open_http_svc/group_msg_get_simple", Jsons.stringify(body));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查单聊历史漫游消息(老应用拉取,用老密钥)— 数据迁移用
|
||||
* <p>
|
||||
* 与 {@link #getRoamMsg} 同语义,但用指定老应用密钥调 callApiAs(迁移拉取消耗老应用配额)。
|
||||
*/
|
||||
public String getRoamMsgAs(String fromAccount, String toAccount, int maxCnt, long minTime, long maxInterval,
|
||||
long srcSdkAppId, String srcSecretKey) {
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("From_Account", fromAccount);
|
||||
body.put("To_Account", toAccount);
|
||||
body.put("MaxCnt", maxCnt);
|
||||
body.put("MinTime", minTime);
|
||||
body.put("MaxTimeInterval", maxInterval);
|
||||
return callApiAs("openim_admin/get_roam_msg", Jsons.stringify(body), srcSdkAppId, srcSecretKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查群历史消息(老应用拉取,用老密钥,支持 ReqMsgSeq 分页)— 数据迁移用
|
||||
*
|
||||
* @param reqMsgSeq 分页游标(上次最旧消息 seq;≤0 表示从最新开始)
|
||||
*/
|
||||
public String getGroupMsgAs(String groupId, int reqMsgNumber, long reqMsgSeq,
|
||||
long srcSdkAppId, String srcSecretKey) {
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("GroupId", groupId);
|
||||
body.put("ReqMsgNumber", reqMsgNumber);
|
||||
if (reqMsgSeq > 0) {
|
||||
body.put("ReqMsgSeq", reqMsgSeq);
|
||||
}
|
||||
return callApiAs("group_open_http_svc/group_msg_get_simple", Jsons.stringify(body), srcSdkAppId, srcSecretKey);
|
||||
}
|
||||
|
||||
// ==================== 群迁移相关(T14 S3) ====================
|
||||
|
||||
/**
|
||||
@@ -384,8 +426,20 @@ public class TencentImClient {
|
||||
+ "\",\"To_Account\":\"" + toAccount
|
||||
+ "\",\"MsgTimeStamp\":" + msgTimeStamp
|
||||
+ ",\"MsgBody\":" + (msgBodyJson == null ? "[]" : msgBodyJson) + "}";
|
||||
String resp = callApi("openim_http_svc/import_msg", body);
|
||||
return isOk(resp);
|
||||
// V3: 消息导入密集调用易触主应用限流,捕获 429 限速重试;耗尽或非 429 返回 false 跳过该条
|
||||
for (int attempt = 0; attempt <= migrateImportMaxRetry; attempt++) {
|
||||
try {
|
||||
String resp = callApi("openim_http_svc/import_msg", body);
|
||||
return isOk(resp);
|
||||
} catch (BizException e) {
|
||||
if (e.getCode() != 429 || attempt == migrateImportMaxRetry) {
|
||||
log.warn("导入单聊消息失败 from={} to={} ts={} : {}", fromAccount, toAccount, msgTimeStamp, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
sleepRetry();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,8 +454,33 @@ public class TencentImClient {
|
||||
+ "\",\"From_Account\":\"" + (fromAccount == null ? "" : fromAccount)
|
||||
+ "\",\"MsgTimeStamp\":" + msgTimeStamp
|
||||
+ ",\"SyncFromOldSystem\":1,\"MsgBody\":" + (msgBodyJson == null ? "[]" : msgBodyJson) + "}";
|
||||
String resp = callApi("group_open_http_svc/import_group_msg", body);
|
||||
return isOk(resp);
|
||||
// V3: 消息导入密集调用易触主应用限流,捕获 429 限速重试;耗尽或非 429 返回 false 跳过该条
|
||||
for (int attempt = 0; attempt <= migrateImportMaxRetry; attempt++) {
|
||||
try {
|
||||
String resp = callApi("group_open_http_svc/import_group_msg", body);
|
||||
return isOk(resp);
|
||||
} catch (BizException e) {
|
||||
if (e.getCode() != 429 || attempt == migrateImportMaxRetry) {
|
||||
log.warn("导入群消息失败 group={} from={} ts={} : {}", groupId, fromAccount, msgTimeStamp, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
sleepRetry();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息导入限速重试间隔(T14 V3)
|
||||
* <p>
|
||||
* 429 配额超限时 sleep 后重试;线程被中断则提前返回(中断状态已恢复,由上层决定是否继续)。
|
||||
*/
|
||||
private void sleepRetry() {
|
||||
try {
|
||||
Thread.sleep(migrateImportRetryMs);
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 关系链迁移相关(T14 S5) ====================
|
||||
|
||||
Reference in New Issue
Block a user