diff --git a/apps/api/src/server.ts b/apps/api/src/server.ts index 9d03d4a..900d6e6 100644 --- a/apps/api/src/server.ts +++ b/apps/api/src/server.ts @@ -250,9 +250,9 @@ export const app = new Elysia() }); app.listen(3000, async () => { - log.info({ port: 3000 }, "server started") if (cluster.worker?.id === 1) { - await syncService.nextSync().catch((err) => log.error({ err }, "failed to resume product sync queue")); + log.info({ port: 3000 }, "server started") + await syncService.syncNext().catch((err) => log.error({ err }, "failed to resume product sync queue")); } }); diff --git a/apps/api/src/services/sync.ts b/apps/api/src/services/sync.ts index 4da95a1..62e0c7c 100644 --- a/apps/api/src/services/sync.ts +++ b/apps/api/src/services/sync.ts @@ -21,6 +21,7 @@ export class SyncService { async sync(queuedSync: QueuedSync) { let id = queuedSync.id ?? null; + let freedSlot = false; try { log.info("starting sync run"); await this.productSyncer.sync({ @@ -31,13 +32,14 @@ export class SyncService { printful_product_id_filter: queuedSync.filter?.printfulProductIds ?? null, }; if (id) { - // Guard against another worker/machine having already claimed - // this queued row between `queue.front()` and now. const result = await db.updateTable("product_syncs") .set(values) .where("id", "=", id) .where("started_at", "is", null) .executeTakeFirst(); + + // Guard against another worker/machine having already claimed + // this queued row between `queue.front()` and now. if (result.numUpdatedRows === 0n) throw new AlreadyClaimedError(); } else { @@ -61,9 +63,7 @@ export class SyncService { .set({ syncing_printful_product_ids: [], ended_at: completionDate }) .where("id", "=", id) .execute(); - - // Sync next item in queue - await this.nextSync(); + freedSlot = true; } }); } @@ -77,9 +77,8 @@ export class SyncService { 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) { + // If active sync has been syncing for 10 min (600000ms), clear it and retry this sync + if (Date.now() - (activeSync.started_at?.getTime() ?? 0) > 600000) { log.info("already active sync exceeded timeout"); await db.updateTable("product_syncs") .set({ syncing_printful_product_ids: [], ended_at: new Date(), has_failed: true }) @@ -98,14 +97,18 @@ export class SyncService { .set({ syncing_printful_product_ids: [], ended_at: new Date(), has_failed: true }) .where("id", "=", id) .execute(); + freedSlot = true; } throw err; } - + } + finally { + if (freedSlot) + this.syncNext().catch((err) => log.error({ err }, "failed to process next queued sync")); } } - async nextSync() { + async syncNext() { const nextSync = await this.queue.front(); if (nextSync) { await this.sync({