This commit is contained in:
zjf committed 2026-11-12 20:03:44 +08:00
1 parent 26a530feba
commit 350258b881
4 files changed
+27 -11

No files matched your search

@@ -53,7 +53,7 @@ public class SmHotelDownstreamChannelConfigDTO {
@Schema(description = "hotel/apartment 每分钟上限,默认 600;≤0 关闭")
private Integer rateLimitHotelApartmentPerMin;
@Schema(description = "product/daily 每分钟上限,默认 300;≤0 关闭")
@Schema(description = "product/daily 每分钟上限,默认 150(环启 2026-10-26);≤0 关闭")
private Integer rateLimitProductDailyPerMin;
@Schema(description = "慧订 hoteldatepush 出站 QPS,默认 5;≤0 关闭")
@@ -112,4 +112,7 @@ public class SmHotelDownstreamChannelConfigDTO {
@Schema(description = "本地改价/库存/房态后是否自动推本伙伴;大批量补数可临时 false,默认 true(未配则跟进程级)")
private Boolean resourceAutoPushEnabled;
@Schema(description = "全量/日更推送酒店并发;环启建议 ≤3,默认 2;1=串行")
private Integer resourcePushConcurrency;
}
@@ -67,8 +67,8 @@ public class HotelDownstreamProperties {
/** /hotel/sync、/apartment/sync 每分钟上限(环启文档 600) */
private int rateLimitHotelApartmentPerMin = 600;
/** /product/sync、/daily/sync 每分钟上限(环启文档 300) */
private int rateLimitProductDailyPerMin = 300;
/** /product/sync、/daily/sync 每分钟上限(环启文档 2026-10-26 起 150) */
private int rateLimitProductDailyPerMin = 150;
/**
* 慧订 /splider/hoteldatepush 出站 QPS(对方已限流)。
@@ -193,8 +193,8 @@ public class HotelDownstreamProperties {
private String resourcePushCron = "0 30 2 * * ?";
/**
* 下游全量推酒店并发(圣诺等 HTTP 出站)。1=串行;建议 4~8。
* 对方限流时报错再调低。伙伴 YAML 可覆盖。
* 下游全量推酒店并发。1=串行。
* 环启文档建议并发≤3(产品/日历写重);默认 2。圣诺若对方宽松可在 YAML 调高。
*/
private int resourcePushConcurrency = 6;
private int resourcePushConcurrency = 2;
}
@@ -187,14 +187,17 @@ public class HuanqiDownstreamHotelAdapter implements DownstreamHotelAdapter {
}
}
/** 按 appKey + 接口组做分钟窗限流(多实例共享 Redis) */
/**
* 按 appKey + 接口组做分钟窗限流(多实例共享 Redis)。
* 超限时必须 decrement 退回占用并等待,禁止「等超时仍继续」——否则会把对方打到「访问过于频繁」。
*/
private void acquireRatePermit(HotelDownstreamProperties props, String path) {
int limit = resolveRateLimit(props, path);
if (limit <= 0 || StrUtil.isBlank(props.getAppKey())) {
return;
}
String group = rateGroup(path);
for (int i = 0; i < 60; i++) {
for (int i = 0; i < 120; i++) {
long minute = System.currentTimeMillis() / 60_000L;
String key = RATE_KEY + props.getAppKey() + ":" + group + ":" + minute;
Long n = redisTemplate.opsForValue().increment(key);
@@ -204,10 +207,17 @@ public class HuanqiDownstreamHotelAdapter implements DownstreamHotelAdapter {
if (n == null || n <= limit) {
return;
}
long wait = 60_000L - (System.currentTimeMillis() % 60_000L) + 20L;
sleepQuiet(Math.min(wait, 5000L));
// 超限:退回本次数,避免循环里反复 increment 把窗口计数打爆
try {
redisTemplate.opsForValue().decrement(key);
}
catch (Exception ignored) {
// ignore
}
long wait = 60_000L - (System.currentTimeMillis() % 60_000L) + 80L;
sleepQuiet(Math.min(Math.max(wait, 200L), 3000L));
}
log.warn("|{}|限流等待超时仍继续|appKey={}|path={}|limit={}|", TAG, props.getAppKey(), path, limit);
throw new CheckedException("下游限流等待超时(" + group + "≤" + limit + "/min),请降低推送并发或错峰再试");
}
private static int resolveRateLimit(HotelDownstreamProperties props, String path) {
@@ -409,6 +409,9 @@ public class SmHotelChannelConfigServiceImpl extends ServiceImpl<SmHotelChannelC
if (dto.getResourceAutoPushEnabled() != null) {
target.setResourceAutoPushEnabled(dto.getResourceAutoPushEnabled());
}
if (dto.getResourcePushConcurrency() != null && dto.getResourcePushConcurrency() > 0) {
target.setResourcePushConcurrency(dto.getResourcePushConcurrency());
}
}
private void overlayShangyou(ShangyouHotelProperties target, SmHotelShangyouChannelConfigDTO dto) {