fix(lastleg): pace master data pages without holding collection leases

This commit is contained in:
2026-10-14 16:56:40 +08:00
parent 63883f4ffd
commit 1112d11c80
4 changed files with 26 additions and 5 deletions
@@ -39,11 +39,14 @@ class SelfopMasterDataCollectorTest {
when(client.products(any(),eq(1),eq(100))).thenReturn(new LingxingAnalyticsClient.Page<>(List.of(product("C","SKU"),product("D","SKU")),1,100,2L,1));
when(data.productCount(20L,"A")).thenReturn(2L);
collector.collect(task,run,lease);
verify(client,never()).products(any(),anyInt(),anyInt());
collector.collect(task,run,lease);
assertEquals("PUBLISHED",run.getStatus());assertEquals("SUCCEEDED",task.getStatus());assertEquals(3L,run.getUniqueObjectCount());
verify(data,times(2)).insertProduct(anyLong(),eq(20L),eq("A"),any(),any());verify(service,never()).yield(anyLong(),anyLong(),any());
verify(data,times(2)).insertProduct(anyLong(),eq(20L),eq("A"),any(),any());verify(service,times(1)).yield(anyLong(),anyLong(),any());
}
@Test void countMismatchCannotPublish(){
when(client.products(any(),eq(1),eq(100))).thenReturn(new LingxingAnalyticsClient.Page<>(List.of(product("C","SKU")),1,100,1L,1));
collector.collect(task,run,lease);
assertEquals("SELFOP_MASTER_COUNT_MISMATCH",assertThrows(IllegalStateException.class,()->collector.collect(task,run,lease)).getMessage());
assertNotEquals("PUBLISHED",run.getStatus());
}
@@ -63,7 +66,14 @@ class SelfopMasterDataCollectorTest {
}
when(data.productCount(20L,"A")).thenReturn(600L);
collector.collect(task,run,lease);verify(service).yield(10L,20L,lease);assertNotEquals("PUBLISHED",run.getStatus());
collector.collect(task,run,lease);assertEquals("PUBLISHED",run.getStatus());verify(client,times(1)).customers(any(),eq(1),eq(1000));
verify(client,never()).products(any(),anyInt(),anyInt());
for(int page=1;page<=6;page++){
collector.collect(task,run,lease);
verify(client,times(page)).products(any(),anyInt(),anyInt());
if(page<6)assertNotEquals("PUBLISHED",run.getStatus());
}
assertEquals("PUBLISHED",run.getStatus());verify(client,times(1)).customers(any(),eq(1),eq(1000));
verify(service,times(6)).yield(10L,20L,lease);
verify(data,times(600)).insertProduct(anyLong(),eq(20L),eq("A"),any(),any());
}
@Test void changedTotalRejectsBeforePersistence(){
@@ -326,6 +326,16 @@ class SelfopTaskServiceTest {
verifyNoInteractions(tasks, runs, scopes, accounts);
}
@Test void masterDataYieldPersistsFiveSecondsWithoutChangingOrdinaryScheduling() {
var task=task("RUNNING");task.setTaskType("MASTER_DATA");
var run=run("FETCHING");when(locks.lockTask(1L)).thenReturn(task);when(locks.lockRun(20L)).thenReturn(run);
service.yield(1L,20L,lease);
assertThat(task.getNextRetryAtUtc()).isEqualTo(task.getUpdatedAt().plusSeconds(5));
assertThat(run.getStatus()).isEqualTo("YIELDED");
task.setTaskType("BACKFILL");task.setStatus("RUNNING");run.setStatus("FETCHING");
service.yield(1L,20L,lease);
assertThat(task.getNextRetryAtUtc()).isEqualTo(task.getUpdatedAt().plusSeconds(1));
}
@Test void budgetYieldDoesNotBecomeFailedAttemptOrClearApplyBarrier() {
var task = task("RUNNING");
task.setAttemptCount(99);