Merge pull request #33481 from walsm232/fix/catalog-refresh-state-deadlock

fix(catalog): Fix catalog refresh_state deadlock when running multiple replicas
This commit is contained in:
Fredrik Adelöw
2026-03-24 14:21:18 +01:00
committed by GitHub
2 changed files with 12 additions and 4 deletions
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
Fixed a deadlock in the catalog processing loop that occurred when running multiple replicas. The `getProcessableEntities` method used `SELECT ... FOR UPDATE SKIP LOCKED` to prevent concurrent processors from claiming the same rows, but the call was not wrapped in a transaction, so the row locks were released before the subsequent `UPDATE` executed. This allowed multiple replicas to select and update overlapping rows, causing PostgreSQL deadlock errors (code 40P01).
@@ -142,10 +142,13 @@ export class DefaultCatalogProcessingEngine {
pollingIntervalMs: this.pollingIntervalMs,
loadTasks: async count => {
try {
const { items } =
await this.processingDatabase.getProcessableEntities(this.knex, {
processBatchSize: count,
});
const { items } = await this.processingDatabase.transaction(
async tx => {
return this.processingDatabase.getProcessableEntities(tx, {
processBatchSize: count,
});
},
);
return items;
} catch (error) {
this.logger.warn('Failed to load processing items', error);