diff --git a/server/src/main/java/org/eclipse/openvsx/scanning/ExtensionScanCompletionService.java b/server/src/main/java/org/eclipse/openvsx/scanning/ExtensionScanCompletionService.java index cb7fd4989..1b5d09fda 100644 --- a/server/src/main/java/org/eclipse/openvsx/scanning/ExtensionScanCompletionService.java +++ b/server/src/main/java/org/eclipse/openvsx/scanning/ExtensionScanCompletionService.java @@ -92,11 +92,12 @@ public ExtensionScanCompletionService( /** * Check completion for a single scan, catching and logging any errors. - * + *

* Called inline after scanner jobs finish (within existing transaction). * Errors are logged but don't fail the caller - the recovery service * will catch any missed completions on next restart. */ + @Transactional public void checkCompletionSafely(String scanId) { try { checkSingleScanCompletion(scanId); @@ -107,10 +108,10 @@ public void checkCompletionSafely(String scanId) { /** * Check completion for a single scan (event-driven). - * + *

* Called by checkCompletionSafely after scanner jobs finish. * Also called directly by the recovery service. - * + *

* Note: @Transactional needed for direct calls from recovery service. * When called via checkCompletionSafely, participates in existing transaction. */ @@ -150,19 +151,19 @@ public void checkSingleScanCompletion(String scanId) { /** * Process completed scans and activate extensions when all scans pass. - * + *

* FALLBACK: Runs every 5 minutes using JobRunr distributed scheduling. * Only one pod executes this at a time (distributed lock). - * + *

* IMPORTANT: Primary completion checking is EVENT-DRIVEN via checkSingleScanCompletion() * which is called immediately when each scanner job finishes. This polling job is only * a safety net for edge cases (missed events, server crashes, etc.). - * + *

* To avoid blocking workers during high load: * - Runs less frequently (every 5 minutes instead of 1) * - Processes at most MAX_SCANS_PER_CYCLE scans per run * - Prioritizes oldest scans first (FIFO) - * + *

* Strategy: * 1. Find all ExtensionScanResult records in SCANNING status (oldest first) * 2. For each one (up to limit), check if all associated ScanJobs are complete @@ -266,18 +267,18 @@ private Boolean processSingleScan(ExtensionScan scanResult) { /** * Determine if we should proceed with scan completion or wait for more jobs. - * + *

* This method dynamically checks which scanners are CURRENTLY active and ensures * all active scanners have jobs (terminal or not). - * + *

* Strategy: * 1. Get list of currently active scanners from ScannerRegistry * 2. Check which scanners have jobs for this extension * 3. If missing scanners AND > 5 minutes since scan started → create jobs for new scanners * 4. If all active scanners have terminal jobs → proceed with completion - * + *

* Edge cases handled: - * + *

* 1. Scanner Removed: Jobs for removed scanners are ignored (not in active list) * 2. Scanner Added: After 5 minutes, create jobs for new scanners * 3. Jobs Still Being Created: Wait < 5 minutes for initial job creation @@ -366,7 +367,7 @@ private boolean shouldProceedWithCompletion(ExtensionScan scanResult, List * This allows new scanners to retroactively scan extensions that are still * in the scanning phase. */ @@ -421,7 +422,7 @@ private boolean allJobsTerminal(List jobs) { /** * Process a completed scan group and activate extension if scans passed. - * + *

* Logic: * 1. Check if any jobs FAILED * 2. Load all threats from all jobs @@ -626,7 +627,7 @@ private boolean completeExtensionScan(String scanId, List jobs) { /** * Find the ExtensionVersion associated with an ExtensionScan. - * + *

* Uses the namespace/extension/version/platform from the scan record * to look up the actual ExtensionVersion entity. */ diff --git a/server/src/main/java/org/eclipse/openvsx/scanning/RemoteScanner.java b/server/src/main/java/org/eclipse/openvsx/scanning/RemoteScanner.java index 8edd8e06b..8f02989af 100644 --- a/server/src/main/java/org/eclipse/openvsx/scanning/RemoteScanner.java +++ b/server/src/main/java/org/eclipse/openvsx/scanning/RemoteScanner.java @@ -113,13 +113,14 @@ public Scanner.Invocation startScan(@Nonnull Command command) throws ScannerExce try (var extensionFile = scanFileService.getExtensionFile(command.extensionVersionId())) { File file = extensionFile.getPath().toFile(); + String fileName = extensionFile.getResource() != null ? extensionFile.getResource().getName() : file.getName(); // Copy operation to avoid mutating shared config (thread safety) RemoteScannerProperties.HttpOperation startOp = configOp.copy(); // Process URL and headers with placeholders Map placeholders = new HashMap<>(); - placeholders.put("fileName", file.getName()); + placeholders.put("fileName", fileName); processOperation(startOp, placeholders); diff --git a/server/src/main/java/org/eclipse/openvsx/scanning/ScannerConcurrencyDispatcher.java b/server/src/main/java/org/eclipse/openvsx/scanning/ScannerConcurrencyDispatcher.java index 83f920612..e90d73d4a 100644 --- a/server/src/main/java/org/eclipse/openvsx/scanning/ScannerConcurrencyDispatcher.java +++ b/server/src/main/java/org/eclipse/openvsx/scanning/ScannerConcurrencyDispatcher.java @@ -66,7 +66,6 @@ public ScannerConcurrencyDispatcher( */ @Job(name = "Scanner concurrency dispatcher", retries = 0) @Recurring(id = "scanner-concurrency-dispatcher", interval = "PT15S") - @Transactional public void dispatch() { boolean anyLimited = scannerRegistry.getAllScanners().stream() .anyMatch(s -> s.getMaxConcurrency() > 0); diff --git a/server/src/main/java/org/eclipse/openvsx/util/TempFile.java b/server/src/main/java/org/eclipse/openvsx/util/TempFile.java index df5508ac9..62ece2b80 100644 --- a/server/src/main/java/org/eclipse/openvsx/util/TempFile.java +++ b/server/src/main/java/org/eclipse/openvsx/util/TempFile.java @@ -23,19 +23,13 @@ public class TempFile implements Closeable { private FileResource resource; private Namespace namespace; - /** Original name of the file (e.g., path within archive) */ - private String originalName; - - /** SHA256 hash of the file content */ - private String sha256Hash; - public TempFile(String prefix, String suffix) throws IOException { path = Files.createTempFile(prefix, suffix); } /** * Create a TempFile from an existing path. - * + *

* Used when extracting files to a pre-created temp location. * The file will be deleted when close() is called. * @@ -65,22 +59,6 @@ public void setNamespace(Namespace namespace) { this.namespace = namespace; } - public String getOriginalName() { - return originalName; - } - - public void setOriginalName(String originalName) { - this.originalName = originalName; - } - - public String getSha256Hash() { - return sha256Hash; - } - - public void setSha256Hash(String sha256Hash) { - this.sha256Hash = sha256Hash; - } - @Override public void close() throws IOException { Files.delete(path);