From 4d23052644e997be35e9e60834eedfcbd03ecb30 Mon Sep 17 00:00:00 2001 From: Dominic Ferrando Date: Fri, 3 Jul 2026 14:39:31 -0400 Subject: [PATCH] Add protection against stale sync records --- apps/api/src/services/sync.ts | 38 +++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/apps/api/src/services/sync.ts b/apps/api/src/services/sync.ts index fda6333..11b61b0 100644 --- a/apps/api/src/services/sync.ts +++ b/apps/api/src/services/sync.ts @@ -94,19 +94,35 @@ export class SyncService { }); } catch (err) { - const isActiveSyncConflict = err instanceof DatabaseError && err.code === "23505" && (await this.getActiveSync()); - if (isActiveSyncConflict) { - log.info("sync already active, enqueuing next sync"); - await this.queue.enqueue(opt); - return; + const activeSync = await this.getActiveSync(); + + const activeSyncConflict = activeSync && err instanceof DatabaseError && err.code === "23505"; + if (activeSyncConflict) { + // If active sync has been syncing for too long, clear it and retry this sync + const TEN_MIN = 600000; + if (Date.now() - (activeSync.started_at?.getTime() ?? 0) > TEN_MIN) { + log.info("already active sync exceeded timeout"); + await db.updateTable("product_syncs") + .set({ syncing_printful_product_ids: [], ended_at: new Date(), has_failed: true }) + .where("id", "=", activeSync.id) + .execute(); + await this.sync(opt); + } + else { + log.info("sync already active, enqueuing next sync"); + await this.queue.enqueue(opt); + } } - else if (id) { - await db.updateTable("product_syncs") - .set({ syncing_printful_product_ids: [], ended_at: new Date(), has_failed: true }) - .where("id", "=", id) - .execute(); + else { + if (id) { + await db.updateTable("product_syncs") + .set({ syncing_printful_product_ids: [], ended_at: new Date(), has_failed: true }) + .where("id", "=", id) + .execute(); + } + throw err; } - throw err; + } }