Repository navigation
fix: guard scan recovery on startup with a Postgres advisory lock - #2104
Merged
Merged
Conversation
recoverOnStartup() fires independently in every instance's own JVM on ApplicationReadyEvent, with no cross-pod coordination. During a rolling update with several pods starting in the same window, each one runs the whole recovery pass: - Duplicate log lines (the reported symptom in #2082), from recoverStaleScans() logging the same scan on every instance. - Genuine duplicate work: recoverPendingJobs() can re-enqueue the same QUEUED sync job twice, and recoverValidatingScan() can submit the same VALIDATING scan for scanning twice. Guard the whole pass with a transaction-scoped Postgres advisory lock (pg_try_advisory_xact_lock), so only one instance actually runs recovery per startup window; the rest skip with a debug log. Chose the transaction-scoped variant over the session-scoped one to avoid lock-leak risk under HikariCP connection pooling - it releases automatically on commit/rollback, no explicit unlock needed. Fixes #2082 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Member
cstamas
approved these changes
Aug 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
ExtensionScanJobRecoveryService.recoverOnStartup()fires independently in every instance's own JVM onApplicationReadyEvent, with no cross-pod coordination. During a rolling update with several pods starting in the same window, each one runs the whole recovery pass, which causes:recoverPendingJobs()can re-enqueue the sameQUEUEDsync scanner job twice, andrecoverValidatingScan()can submit the sameVALIDATINGscan for scanning twice.How
Guards the whole
recoverOnStartup()pass with a Postgres transaction-scoped advisory lock (pg_try_advisory_xact_lock). Only the instance that acquires the lock runs recovery; the rest skip with a debug log and rely on the winner. Chose the transaction-scoped variant over the session-scoped one to avoid lock-leak risk under HikariCP connection pooling - it releases automatically on commit/rollback, with no explicit unlock call needed.Testing
Added
ExtensionScanJobRecoveryServiceTest, covering:recoverOnStartup()'s control flow: skips recovery when the lock can't be acquired, runs it when it can, and doesn't even attempt the lock when scanning is disabled../gradlew test --tests 'org.eclipse.openvsx.scanning.*'passes locally.Fixes #2082