mirror of
https://github.com/booklore-app/booklore.git
synced 2026-02-18 00:17:53 +01:00
fix(library-service): prevent concurrent library scans with a tracking set (#2637)
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
This commit is contained in:
@@ -38,6 +38,7 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -45,6 +46,17 @@ import java.util.stream.Collectors;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class LibraryService {
|
public class LibraryService {
|
||||||
|
|
||||||
|
private static final Set<Long> scanningLibraries = ConcurrentHashMap.newKeySet();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a library is currently being scanned.
|
||||||
|
* Can be used by other components (e.g., file watcher) to avoid processing
|
||||||
|
* files while a full scan is in progress.
|
||||||
|
*/
|
||||||
|
public static boolean isLibraryScanning(long libraryId) {
|
||||||
|
return scanningLibraries.contains(libraryId);
|
||||||
|
}
|
||||||
|
|
||||||
private final LibraryRepository libraryRepository;
|
private final LibraryRepository libraryRepository;
|
||||||
private final LibraryPathRepository libraryPathRepository;
|
private final LibraryPathRepository libraryPathRepository;
|
||||||
private final BookRepository bookRepository;
|
private final BookRepository bookRepository;
|
||||||
@@ -125,10 +137,16 @@ public class LibraryService {
|
|||||||
|
|
||||||
if (!newPaths.isEmpty()) {
|
if (!newPaths.isEmpty()) {
|
||||||
SecurityContextVirtualThread.runWithSecurityContext(() -> {
|
SecurityContextVirtualThread.runWithSecurityContext(() -> {
|
||||||
|
if (!scanningLibraries.add(libraryId)) {
|
||||||
|
log.warn("Library {} is already being scanned, skipping duplicate process request", libraryId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
libraryProcessingService.processLibrary(libraryId);
|
libraryProcessingService.processLibrary(libraryId);
|
||||||
} catch (InvalidDataAccessApiUsageException e) {
|
} catch (InvalidDataAccessApiUsageException e) {
|
||||||
log.debug("InvalidDataAccessApiUsageException - Library id: {}", libraryId);
|
log.debug("InvalidDataAccessApiUsageException - Library id: {}", libraryId);
|
||||||
|
} finally {
|
||||||
|
scanningLibraries.remove(libraryId);
|
||||||
}
|
}
|
||||||
log.info("Parsing task completed!");
|
log.info("Parsing task completed!");
|
||||||
});
|
});
|
||||||
@@ -169,10 +187,16 @@ public class LibraryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SecurityContextVirtualThread.runWithSecurityContext(() -> {
|
SecurityContextVirtualThread.runWithSecurityContext(() -> {
|
||||||
|
if (!scanningLibraries.add(libraryId)) {
|
||||||
|
log.warn("Library {} is already being scanned, skipping duplicate process request", libraryId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
libraryProcessingService.processLibrary(libraryId);
|
libraryProcessingService.processLibrary(libraryId);
|
||||||
} catch (InvalidDataAccessApiUsageException e) {
|
} catch (InvalidDataAccessApiUsageException e) {
|
||||||
log.debug("InvalidDataAccessApiUsageException - Library id: {}", libraryId);
|
log.debug("InvalidDataAccessApiUsageException - Library id: {}", libraryId);
|
||||||
|
} finally {
|
||||||
|
scanningLibraries.remove(libraryId);
|
||||||
}
|
}
|
||||||
log.info("Parsing task completed!");
|
log.info("Parsing task completed!");
|
||||||
});
|
});
|
||||||
@@ -184,6 +208,10 @@ public class LibraryService {
|
|||||||
libraryRepository.findById(libraryId).orElseThrow(() -> ApiError.LIBRARY_NOT_FOUND.createException(libraryId));
|
libraryRepository.findById(libraryId).orElseThrow(() -> ApiError.LIBRARY_NOT_FOUND.createException(libraryId));
|
||||||
|
|
||||||
SecurityContextVirtualThread.runWithSecurityContext(() -> {
|
SecurityContextVirtualThread.runWithSecurityContext(() -> {
|
||||||
|
if (!scanningLibraries.add(libraryId)) {
|
||||||
|
log.warn("Library {} is already being scanned, skipping duplicate rescan request", libraryId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
RescanLibraryContext context = RescanLibraryContext.builder()
|
RescanLibraryContext context = RescanLibraryContext.builder()
|
||||||
.libraryId(libraryId)
|
.libraryId(libraryId)
|
||||||
@@ -193,6 +221,8 @@ public class LibraryService {
|
|||||||
log.debug("InvalidDataAccessApiUsageException - Library id: {}", libraryId);
|
log.debug("InvalidDataAccessApiUsageException - Library id: {}", libraryId);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Error while parsing library books", e);
|
log.error("Error while parsing library books", e);
|
||||||
|
} finally {
|
||||||
|
scanningLibraries.remove(libraryId);
|
||||||
}
|
}
|
||||||
log.info("Parsing task completed!");
|
log.info("Parsing task completed!");
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user