|
|
@@ -28,6 +28,7 @@ public class AdminAdvertiserListServiceImpl implements IAdminAdvertiserListServi
|
|
|
|
|
|
@Override
|
|
|
public JSONObject bytedanceAdvertiserSync(Long adminAdvertiserId, String accessToken) {
|
|
|
+ long syncStart = System.currentTimeMillis();
|
|
|
JSONObject returnJson = new JSONObject();
|
|
|
// 1. 拉授权主体列表,确定要展开的组织集合(与字节授权回调同口径)
|
|
|
JSONObject authResult = getBytedanceAuthAdvertisers(accessToken);
|
|
|
@@ -52,14 +53,16 @@ public class AdminAdvertiserListServiceImpl implements IAdminAdvertiserListServi
|
|
|
List<Long> customerAccounts = authResult.getJSONArray("customerAccounts").toJavaList(Long.class);
|
|
|
List<BytedanceAdvertiserList> normalAccounts = authResult.getJSONArray("normalAccounts")
|
|
|
.toJavaList(BytedanceAdvertiserList.class);
|
|
|
- log.info("授权主体下纵横管家/操作员数:{},NORMAL投放主体数:{},adminAdvertiserId:{}",
|
|
|
- customerAccounts.size(), normalAccounts.size(), adminAdvertiserId);
|
|
|
+ log.info("授权主体下纵横管家/操作员:{},NORMAL投放主体数:{},归属管家:{}",
|
|
|
+ customerAccounts, normalAccounts.size(), adminAdvertiserId);
|
|
|
|
|
|
// 2. 串行拉各组织第 1 页确定总页数(每组织仅 1 次请求,代价可忽略)
|
|
|
int pageSize = 100;
|
|
|
+ long phaseStart = System.currentTimeMillis();
|
|
|
List<CcOrgFetchPlan> plans = new ArrayList<>();
|
|
|
boolean allSuccess = true;
|
|
|
for (Long ccAccountId : customerAccounts) {
|
|
|
+ long orgFirstPageStart = System.currentTimeMillis();
|
|
|
CcPageResult firstPage = fetchCcAdvertiserPageWithRetry(adminAdvertiserId, ccAccountId, accessToken, 1, pageSize);
|
|
|
if (firstPage == null) {
|
|
|
// 组织首页拉取失败时账户集合不完整,本次不做失效清理,避免误删
|
|
|
@@ -68,9 +71,13 @@ public class AdminAdvertiserListServiceImpl implements IAdminAdvertiserListServi
|
|
|
continue;
|
|
|
}
|
|
|
plans.add(new CcOrgFetchPlan(ccAccountId, Math.max(firstPage.getTotalPage(), 1), firstPage.getIds()));
|
|
|
+ log.info("字节任务-组织首页拉取耗时={}ms, ccAccountId={}, totalPage={}, 账户数={}",
|
|
|
+ System.currentTimeMillis() - orgFirstPageStart, ccAccountId, firstPage.getTotalPage(), firstPage.getIds().size());
|
|
|
}
|
|
|
+ log.info("字节任务-组织首页阶段总耗时={}ms, 组织数={}", System.currentTimeMillis() - phaseStart, plans.size());
|
|
|
|
|
|
// 3. 全部组织的其余分页提交线程池并行拉取
|
|
|
+ phaseStart = System.currentTimeMillis();
|
|
|
ExecutorService executor = Executors.newFixedThreadPool(10);
|
|
|
List<Future<CcPageResult>> futures = new ArrayList<>();
|
|
|
for (CcOrgFetchPlan plan : plans) {
|
|
|
@@ -80,32 +87,43 @@ public class AdminAdvertiserListServiceImpl implements IAdminAdvertiserListServi
|
|
|
}
|
|
|
}
|
|
|
Map<Long, Map<Integer, List<Long>>> idsByOrgPage = new HashMap<>();
|
|
|
+ int successPages = 0;
|
|
|
+ int failedPages = 0;
|
|
|
for (Future<CcPageResult> future : futures) {
|
|
|
try {
|
|
|
CcPageResult result = future.get();
|
|
|
if (result == null || result.getIds() == null) {
|
|
|
allSuccess = false;
|
|
|
+ failedPages++;
|
|
|
continue;
|
|
|
}
|
|
|
+ successPages++;
|
|
|
idsByOrgPage.computeIfAbsent(result.getCcAccountId(), key -> new HashMap<>()).put(result.getPageNumber(), result.getIds());
|
|
|
} catch (InterruptedException | ExecutionException e) {
|
|
|
allSuccess = false;
|
|
|
+ failedPages++;
|
|
|
log.error("多线程请求字节纵横组织账户失败: {}", e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
executor.shutdown();
|
|
|
+ log.info("字节任务-并行分页阶段耗时={}ms, 提交页数={}, 成功页数={}, 失败页数={}",
|
|
|
+ System.currentTimeMillis() - phaseStart, futures.size(), successPages, failedPages);
|
|
|
|
|
|
// 4. 按组织顺序、页序合并,多组织账户取并集
|
|
|
+ long mergeStart = System.currentTimeMillis();
|
|
|
Set<Long> mergedIds = new LinkedHashSet<>();
|
|
|
for (CcOrgFetchPlan plan : plans) {
|
|
|
+ int orgAccountCount = plan.getFirstPageIds().size();
|
|
|
mergedIds.addAll(plan.getFirstPageIds());
|
|
|
Map<Integer, List<Long>> orgPages = idsByOrgPage.getOrDefault(plan.getCcAccountId(), Collections.emptyMap());
|
|
|
for (int page = 2; page <= plan.getTotalPage(); page++) {
|
|
|
List<Long> ids = orgPages.get(page);
|
|
|
if (ids != null) {
|
|
|
+ orgAccountCount += ids.size();
|
|
|
mergedIds.addAll(ids);
|
|
|
}
|
|
|
}
|
|
|
+ log.info("字节任务-组织账户合并:ccAccountId={}, 账户数={}", plan.getCcAccountId(), orgAccountCount);
|
|
|
}
|
|
|
// 授权主体自身的NORMAL投放账户并入(与字节授权回调同口径:自营企业号也是投放主体)
|
|
|
for (BytedanceAdvertiserList normalAccount : normalAccounts) {
|
|
|
@@ -113,17 +131,25 @@ public class AdminAdvertiserListServiceImpl implements IAdminAdvertiserListServi
|
|
|
}
|
|
|
if (!normalAccounts.isEmpty()) {
|
|
|
adminAdvertiserListMapper.replaceBytedanceAdvertiserLists(normalAccounts);
|
|
|
+ log.info("字节任务-NORMAL自营主体写入:{}条", normalAccounts.size());
|
|
|
}
|
|
|
+ log.info("字节任务-分页结果合并耗时={}ms, 多组织并集账户数={}", System.currentTimeMillis() - mergeStart, mergedIds.size());
|
|
|
|
|
|
// 5. 全量同步:所有组织分页均拉取成功才清理存量;任一分页失败则跳过,防止误删
|
|
|
+ int deletedCount = 0;
|
|
|
if (allSuccess) {
|
|
|
+ long deleteStart = System.currentTimeMillis();
|
|
|
if (mergedIds.isEmpty()) {
|
|
|
// 全部组织确认已无账户,按全量同步语义清空该管家存量账户
|
|
|
- adminAdvertiserListMapper.deleteNotInAdvertiserList(adminAdvertiserId, null);
|
|
|
+ deletedCount = adminAdvertiserListMapper.deleteNotInAdvertiserList(adminAdvertiserId, null);
|
|
|
+ log.info("字节任务-全部组织已无账户,清空该管家存量账户:{}条, 耗时={}ms", deletedCount, System.currentTimeMillis() - deleteStart);
|
|
|
} else {
|
|
|
- adminAdvertiserListMapper.deleteNotInAdvertiserList(adminAdvertiserId, new ArrayList<>(mergedIds));
|
|
|
+ deletedCount = adminAdvertiserListMapper.deleteNotInAdvertiserList(adminAdvertiserId, new ArrayList<>(mergedIds));
|
|
|
+ log.info("字节任务-存量过期账户清理:{}条, 耗时={}ms", deletedCount, System.currentTimeMillis() - deleteStart);
|
|
|
}
|
|
|
}
|
|
|
+ log.info("字节任务-全量同步总耗时={}ms, adminAdvertiserId={}, 并集账户数={}, 清理过期账户数={}",
|
|
|
+ System.currentTimeMillis() - syncStart, adminAdvertiserId, mergedIds.size(), deletedCount);
|
|
|
returnJson.put("code", allSuccess ? 200 : 500);
|
|
|
returnJson.put("total", mergedIds.size());
|
|
|
returnJson.put("message", allSuccess ? "全量同步成功,已同步删除过期账户" : "存在拉取失败分页,跳过本次存量账户清理");
|
|
|
@@ -213,6 +239,7 @@ public class AdminAdvertiserListServiceImpl implements IAdminAdvertiserListServi
|
|
|
* 拉取纵横组织单页(account_source=AD,与字节授权回调同口径),成功分页结果入库并返回,失败返回 null
|
|
|
*/
|
|
|
private CcPageResult fetchCcAdvertiserPage(Long adminAdvertiserId, Long ccAccountId, String accessToken, int page, int pageSize) {
|
|
|
+ long requestStart = System.currentTimeMillis();
|
|
|
try {
|
|
|
Thread.sleep(100L);
|
|
|
} catch (InterruptedException e) {
|
|
|
@@ -258,6 +285,8 @@ public class AdminAdvertiserListServiceImpl implements IAdminAdvertiserListServi
|
|
|
if (!advertiserLists.isEmpty()) {
|
|
|
adminAdvertiserListMapper.replaceBytedanceAdvertiserLists(advertiserLists);
|
|
|
}
|
|
|
+ log.info("字节任务-分页请求耗时={}ms, ccAccountId={}, page={}, 账户数={}",
|
|
|
+ System.currentTimeMillis() - requestStart, ccAccountId, page, advertiserLists.size());
|
|
|
List<Long> ids = new ArrayList<>();
|
|
|
for (BytedanceAdvertiserList advertiserList : advertiserLists) {
|
|
|
ids.add(advertiserList.getAdvertiserId());
|