Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor catalog refresh to make it more resilient #516

Merged
merged 2 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions onyxia-api/src/main/java/fr/insee/onyxia/api/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication(scanBasePackages = {"io.github.inseefrlab", "fr.insee.onyxia"})
@EnableAsync(proxyTargetClass = true)
@EnableScheduling
public class Application {

private static final Logger LOGGER = LoggerFactory.getLogger(Application.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,30 @@
import fr.insee.onyxia.api.configuration.Catalogs;
import io.github.inseefrlab.helmwrapper.service.HelmRepoService;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeoutException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Service
public class CatalogRefresher implements ApplicationRunner {
public class CatalogRefresher {

private static final Logger LOGGER = LoggerFactory.getLogger(CatalogRefresher.class);

private final Catalogs catalogs;
private final CatalogLoader catalogLoader;
private final long refreshTime;
private final HelmRepoService helmRepoService;

@Autowired
public CatalogRefresher(
Catalogs catalogs,
CatalogLoader catalogLoader,
HelmRepoService helmRepoService,
@Value("${catalogs.refresh.ms}") long refreshTime) {
Catalogs catalogs, CatalogLoader catalogLoader, HelmRepoService helmRepoService) {
this.catalogs = catalogs;
this.catalogLoader = catalogLoader;
this.helmRepoService = helmRepoService;
this.refreshTime = refreshTime;
}

private void refreshCatalogs() {
Expand Down Expand Up @@ -76,32 +69,18 @@ private void refresh() throws InterruptedException {
refreshCatalogs();
}

@Override
public void run(ApplicationArguments args) throws Exception {
LOGGER.info("Starting catalog refresher...");
@Scheduled(fixedDelayString = "${catalogs.refresh.ms}")
public synchronized void run() {
LOGGER.info("Refreshing catalogs");
try {
refresh();
} catch (InterruptedException e) {
LOGGER.warn("Run method interrupted", e);
Thread.currentThread().interrupt();
} catch (Exception e) {
LOGGER.error("Catalog refreshing failed", e);
}
}

if (refreshTime > 0L) {
Timer timer = new Timer();
TimerTask timerTask =
new TimerTask() {
@Override
public void run() {
LOGGER.info("Refreshing catalogs");
try {
refresh();
} catch (InterruptedException e) {
LOGGER.warn("Timer task interrupted", e);
Thread.currentThread().interrupt();
}
}
};
timer.scheduleAtFixedRate(timerTask, refreshTime, refreshTime);
}
@EventListener(ApplicationReadyEvent.class)
public void initialRefresh() {
run();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.ApplicationArguments;
import org.springframework.test.context.TestPropertySource;

@ExtendWith(MockitoExtension.class)
@TestPropertySource(properties = "catalogs.refresh.ms=1000")
class CatalogRefresherTest {

@Mock private Catalogs catalogs;
Expand All @@ -25,13 +26,11 @@ class CatalogRefresherTest {

@Mock private HelmRepoService helmRepoService;

@Mock private ApplicationArguments applicationArguments;

private CatalogRefresher catalogRefresher;

@BeforeEach
void setUp() {
catalogRefresher = new CatalogRefresher(catalogs, catalogLoader, helmRepoService, 1000);
catalogRefresher = new CatalogRefresher(catalogs, catalogLoader, helmRepoService);
Thread.interrupted(); // Clear any existing interrupted status
}

Expand All @@ -42,7 +41,7 @@ void testInterruptedExceptionHandling() throws Exception {
.when(helmRepoService)
.repoUpdate();

catalogRefresher.run(applicationArguments);
catalogRefresher.run();

verify(helmRepoService).repoUpdate();
verify(catalogLoader, never()).updateCatalog(any(CatalogWrapper.class));
Expand All @@ -56,7 +55,7 @@ void testInterruptedExceptionHandling() throws Exception {
void testTimeoutExceptionHandling() throws Exception {
doThrow(new TimeoutException("Timeout")).when(helmRepoService).repoUpdate();

catalogRefresher.run(applicationArguments);
catalogRefresher.run();

verify(helmRepoService).repoUpdate();
verify(catalogLoader, never()).updateCatalog(any(CatalogWrapper.class));
Expand All @@ -67,7 +66,7 @@ void testTimeoutExceptionHandling() throws Exception {
void testIOExceptionHandling() throws Exception {
doThrow(new IOException("IO error")).when(helmRepoService).repoUpdate();

catalogRefresher.run(applicationArguments);
catalogRefresher.run();

verify(helmRepoService).repoUpdate();
verify(catalogLoader, never()).updateCatalog(any(CatalogWrapper.class));
Expand All @@ -85,7 +84,7 @@ void testSuccessfulRefresh() throws Exception {
when(catalogs.getCatalogs()).thenReturn(List.of(catalogWrapper));
when(helmRepoService.addHelmRepo("location", "id", false, null)).thenReturn("Repo added");

catalogRefresher.run(applicationArguments);
catalogRefresher.run();

verify(helmRepoService).repoUpdate();
verify(helmRepoService, times(1)).addHelmRepo("location", "id", false, null);
Expand Down