diff --git a/src/main/java/com/lion/lionwebsite/Service/SubscriptionRefreshScheduler.java b/src/main/java/com/lion/lionwebsite/Service/SubscriptionRefreshScheduler.java index f5c827b..16e0338 100644 --- a/src/main/java/com/lion/lionwebsite/Service/SubscriptionRefreshScheduler.java +++ b/src/main/java/com/lion/lionwebsite/Service/SubscriptionRefreshScheduler.java @@ -38,6 +38,7 @@ public class SubscriptionRefreshScheduler { private final SubscriptionRefreshService refreshService; private final SubscriptionRefreshPlanner planner; private final PushService pushService; + private final RemoteService remoteService; /** 单个 tick 最多刷新几个账号,避免重启后一批到期账号同时开火。 */ @Value("${subscription.refresh.max-per-tick:2}") @@ -53,11 +54,13 @@ public class SubscriptionRefreshScheduler { public SubscriptionRefreshScheduler(SubMapper subMapper, SubscriptionRefreshService refreshService, SubscriptionRefreshPlanner planner, - PushService pushService) { + PushService pushService, + RemoteService remoteService) { this.subMapper = subMapper; this.refreshService = refreshService; this.planner = planner; this.pushService = pushService; + this.remoteService = remoteService; } /** @@ -97,6 +100,10 @@ public class SubscriptionRefreshScheduler { refreshed++; } reportStale(enabled, now); + // 缓存内容变了就要让备机同步。原先全量刷新后由调用方跟一次同步, + // 改为分散刷新后必须在这里补上,否则备机要等到下一次周期同步才拿到新内容。 + if (refreshed > 0) + remoteService.requestSubscriptionSync(); return refreshed; } diff --git a/src/test/java/com/lion/lionwebsite/Service/SubscriptionRefreshSchedulerTest.java b/src/test/java/com/lion/lionwebsite/Service/SubscriptionRefreshSchedulerTest.java index 0ff1b83..96c53ea 100644 --- a/src/test/java/com/lion/lionwebsite/Service/SubscriptionRefreshSchedulerTest.java +++ b/src/test/java/com/lion/lionwebsite/Service/SubscriptionRefreshSchedulerTest.java @@ -35,12 +35,14 @@ class SubscriptionRefreshSchedulerTest { private SubMapper subMapper; private SubscriptionRefreshService refreshService; private PushService pushService; + private RemoteService remoteService; @BeforeEach void setUp() { subMapper = mock(SubMapper.class); refreshService = mock(SubscriptionRefreshService.class); pushService = mock(PushService.class); + remoteService = mock(RemoteService.class); } /** 用固定时钟构造,使「现在」可控。 */ @@ -49,7 +51,7 @@ class SubscriptionRefreshSchedulerTest { Clock.fixed(instant, ZONE), new Random(42), Duration.ofHours(24), Duration.ofHours(1), Duration.ofMinutes(5)); SubscriptionRefreshScheduler scheduler = new SubscriptionRefreshScheduler( - subMapper, refreshService, planner, pushService); + subMapper, refreshService, planner, pushService, remoteService); scheduler.maxPerTick = 2; scheduler.staleAlertMultiplier = 2.0; return scheduler; @@ -385,6 +387,31 @@ class SubscriptionRefreshSchedulerTest { "铺开的计划应写回内存对象"); } + /** + * 刷新成功后必须通知备机同步。 + * 原先「全量刷新」由调用方跟一次同步;改成按账号分散刷新后,若调度器不自己触发, + * 备机就要等到下一次周期同步才拿到新内容——这个缺口在重构时很容易漏掉。 + */ + @Test + void refreshTriggersStandbySyncWhenSomethingChanged() { + existing(account(1, BASE.toEpochMilli() - MINUTE, BASE.toEpochMilli() - 2 * HOUR)); + refreshSucceedsForAll(); + + scheduler().refreshDueAccounts(); + + verify(remoteService).requestSubscriptionSync(); + } + + /** 本轮没有任何账号到期时不应打扰备机。 */ + @Test + void noRefreshMeansNoStandbySync() { + existing(account(1, BASE.toEpochMilli() + 5 * HOUR, BASE.toEpochMilli())); + + scheduler().refreshDueAccounts(); + + verify(remoteService, never()).requestSubscriptionSync(); + } + /** 已有计划的账号不应被重新排程,否则每次 tick 都会打乱分散效果。 */ @Test void existingScheduleIsNotOverwritten() { diff --git a/src/test/java/com/lion/lionwebsite/Service/SubscriptionRefreshWiringTest.java b/src/test/java/com/lion/lionwebsite/Service/SubscriptionRefreshWiringTest.java index 98df964..4659da4 100644 --- a/src/test/java/com/lion/lionwebsite/Service/SubscriptionRefreshWiringTest.java +++ b/src/test/java/com/lion/lionwebsite/Service/SubscriptionRefreshWiringTest.java @@ -44,6 +44,11 @@ class SubscriptionRefreshWiringTest { return mock(PushService.class); } + @Bean + RemoteService remoteService() { + return mock(RemoteService.class); + } + @Bean SubscriptionRefreshPlanner subscriptionRefreshPlanner() { return new SubscriptionRefreshPlanner(java.time.Clock.systemDefaultZone(), new java.util.Random(), @@ -54,8 +59,9 @@ class SubscriptionRefreshWiringTest { SubscriptionRefreshScheduler subscriptionRefreshScheduler(SubMapper subMapper, SubscriptionRefreshService refreshService, SubscriptionRefreshPlanner planner, - PushService pushService) { - return new SubscriptionRefreshScheduler(subMapper, refreshService, planner, pushService); + PushService pushService, + RemoteService remoteService) { + return new SubscriptionRefreshScheduler(subMapper, refreshService, planner, pushService, remoteService); } }