fix(search): refresh index after version yank

Signed-off-by: dongmucat <1127093059@qq.com>
This commit is contained in:
dongmucat 2026-07-28 11:06:14 +08:00
parent e066277065
commit 082ab489a3
4 changed files with 63 additions and 1 deletions

View file

@ -2,6 +2,7 @@ package com.iflytek.skillhub.search.event;
import com.iflytek.skillhub.domain.event.SkillPublishedEvent;
import com.iflytek.skillhub.domain.event.SkillStatusChangedEvent;
import com.iflytek.skillhub.domain.event.SkillVersionYankedEvent;
import com.iflytek.skillhub.domain.skill.SkillStatus;
import com.iflytek.skillhub.search.SearchIndexService;
import com.iflytek.skillhub.search.SearchRebuildService;
@ -32,6 +33,12 @@ public class SearchIndexEventListener {
searchRebuildService.rebuildBySkill(event.skillId());
}
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
@Async("skillhubEventExecutor")
public void onSkillVersionYanked(SkillVersionYankedEvent event) {
searchRebuildService.rebuildBySkill(event.skillId());
}
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
@Async("skillhubEventExecutor")
public void onSkillStatusChanged(SkillStatusChangedEvent event) {

View file

@ -116,7 +116,12 @@ public class PostgresSearchRebuildService implements SearchRebuildService {
return;
}
toDocument(skillOpt.get()).ifPresent(searchIndexService::index);
Optional<SkillSearchDocument> document = toDocument(skillOpt.get());
if (document.isPresent()) {
searchIndexService.index(document.get());
} else {
searchIndexService.remove(skillId);
}
}
private SearchIndexPayload buildSearchPayload(Skill skill) {
@ -269,6 +274,9 @@ public class PostgresSearchRebuildService implements SearchRebuildService {
}
private Optional<SkillSearchDocument> toDocument(Skill skill) {
if (skill.getLatestVersionId() == null) {
return Optional.empty();
}
Optional<Namespace> namespaceOpt = namespaceRepository.findById(skill.getNamespaceId());
if (namespaceOpt.isEmpty()) {
return Optional.empty();

View file

@ -2,11 +2,16 @@ package com.iflytek.skillhub.search.event;
import com.iflytek.skillhub.domain.event.SkillPublishedEvent;
import com.iflytek.skillhub.domain.event.SkillStatusChangedEvent;
import com.iflytek.skillhub.domain.event.SkillVersionYankedEvent;
import com.iflytek.skillhub.domain.skill.SkillStatus;
import com.iflytek.skillhub.search.SearchIndexService;
import com.iflytek.skillhub.search.SearchRebuildService;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@ -33,4 +38,20 @@ class SearchIndexEventListenerTest {
verify(searchIndexService).remove(42L);
}
@Test
void yankedVersionShouldTriggerSkillRebuild() throws Exception {
SearchRebuildService searchRebuildService = mock(SearchRebuildService.class);
SearchIndexService searchIndexService = mock(SearchIndexService.class);
SearchIndexEventListener listener = new SearchIndexEventListener(searchRebuildService, searchIndexService);
Method handler = Arrays.stream(SearchIndexEventListener.class.getDeclaredMethods())
.filter(method -> Arrays.equals(method.getParameterTypes(), new Class<?>[]{SkillVersionYankedEvent.class}))
.findFirst()
.orElse(null);
assertThat(handler).isNotNull();
handler.invoke(listener, new SkillVersionYankedEvent(42L, 100L, "admin-1"));
verify(searchRebuildService).rebuildBySkill(42L);
}
}

View file

@ -25,12 +25,38 @@ import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class PostgresSearchRebuildServiceTest {
@Test
void rebuildBySkill_shouldRemoveDocumentWhenNoPublishedVersionExists() {
SkillRepository skillRepository = mock(SkillRepository.class);
NamespaceRepository namespaceRepository = mock(NamespaceRepository.class);
SkillVersionRepository skillVersionRepository = mock(SkillVersionRepository.class);
SearchIndexService searchIndexService = mock(SearchIndexService.class);
Skill skill = new Skill(7L, "pending-only", "owner-1", SkillVisibility.NAMESPACE_ONLY);
setField(skill, "id", 42L);
when(skillRepository.findById(42L)).thenReturn(Optional.of(skill));
PostgresSearchRebuildService service = newService(
skillRepository,
namespaceRepository,
skillVersionRepository,
searchIndexService
);
service.rebuildBySkill(42L);
verify(searchIndexService).remove(42L);
verify(searchIndexService, never()).index(any());
}
@Test
void rebuildBySkill_shouldIndexFrontmatterFieldsAndKeywordsWithoutBody() {
SkillRepository skillRepository = mock(SkillRepository.class);