perf(店铺): 后台添加/改名店铺后异步触发一次紫鸟索引刷新——防抖合并2分钟窗口+延迟10秒等事务提交,拿不到锁或失败不影响添加流程,不等5分钟定时轮

This commit is contained in:
2026-09-11 16:54:16 +08:00
parent 51fb77ec25
commit 2a9110ec32
2 changed files with 58 additions and 0 deletions
@@ -26,6 +26,7 @@ public class ShopManageService {
private final ShopManageMapper shopManageMapper;
private final ShopManageGroupService shopManageGroupService;
private final ShopCredentialCryptoService shopCredentialCryptoService;
private final ZiniaoShopIndexRefreshTrigger ziniaoShopIndexRefreshTrigger;
public ShopManagePageVo page(long page, long pageSize, Long groupId, String shopName, Long operatorId, boolean superAdmin) {
long safePage = Math.max(page, 1);
@@ -98,6 +99,7 @@ public class ShopManageService {
entity.setAccount(normalizeRequired(request.getAccount(), "账号不能为空"));
entity.setPassword(shopCredentialCryptoService.encrypt(normalizeRequired(request.getPassword(), "密码不能为空")));
shopManageMapper.insert(entity);
ziniaoShopIndexRefreshTrigger.trigger("create:" + entity.getShopName());
ShopManageEntity saved = getById(entity.getId());
return toItemVo(saved, group.getGroupName());
}
@@ -121,6 +123,7 @@ public class ShopManageService {
entity.setAccount(normalizeRequired(request.getAccount(), "账号不能为空"));
entity.setPassword(shopCredentialCryptoService.encrypt(normalizeRequired(request.getPassword(), "密码不能为空")));
shopManageMapper.updateById(entity);
ziniaoShopIndexRefreshTrigger.trigger("update:" + entity.getShopName());
ShopManageEntity updated = getById(id);
return toItemVo(updated, group.getGroupName());
}
@@ -0,0 +1,55 @@
package com.nanri.aiimage.modules.shopkey.service;
import com.nanri.aiimage.modules.ziniao.service.ZiniaoShopIndexRefreshService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.Duration;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
/**
* 后台店铺添加/改名后异步触发一次紫鸟店铺索引刷新。
* 调用方不阻塞;带防抖(合并窗口内的多次触发);拿不到分布式锁或刷新失败不影响添加流程。
*/
@Service
@Slf4j
public class ZiniaoShopIndexRefreshTrigger {
/** 防抖:触发后 N 分钟内的重复触发合并掉(刷新一轮本身要几十秒)。 */
private static final long DEBOUNCE_MILLIS = Duration.ofMinutes(2).toMillis();
private final ZiniaoShopIndexRefreshService ziniaoShopIndexRefreshService;
private final AtomicLong lastTriggerAtMillis = new AtomicLong(0);
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(runnable -> {
Thread thread = new Thread(runnable, "ziniao-index-refresh-trigger");
thread.setDaemon(true);
return thread;
});
public ZiniaoShopIndexRefreshTrigger(ZiniaoShopIndexRefreshService ziniaoShopIndexRefreshService) {
this.ziniaoShopIndexRefreshService = ziniaoShopIndexRefreshService;
}
public void trigger(String source) {
long now = System.currentTimeMillis();
long last = lastTriggerAtMillis.get();
if (now - last < DEBOUNCE_MILLIS && !lastTriggerAtMillis.compareAndSet(last, now)) {
log.info("[ziniao-index] 触发防抖合并 source={} 距上次触发不足2分钟", source);
return;
}
lastTriggerAtMillis.set(now);
// 延迟 10 秒:等添加事务提交 & 躲开定时轮刚启动的瞬间
executor.schedule(() -> {
try {
ziniaoShopIndexRefreshService.refreshShopIndexManually();
log.info("[ziniao-index] 店铺变动后增量刷新完成 source={}", source);
} catch (Exception ex) {
log.info("[ziniao-index] 店铺变动后触发刷新未执行(可能有定时轮在刷新),source={} msg={}",
source, ex.getMessage());
}
}, 10, TimeUnit.SECONDS);
}
}