Per item sync bugfix and cleanup

This commit is contained in:
Dominic Ferrando
2026-07-01 11:40:21 -04:00
parent 61e8c47abb
commit 2454d68e24
3 changed files with 24 additions and 22 deletions
+8 -14
View File
@@ -101,9 +101,7 @@ export const app = new Elysia()
}) })
.onAfterResponse(({ request, status, path }) => { .onAfterResponse(({ request, status, path }) => {
const skip: Record<string, string[]> = { const skip: Record<string, string[]> = { "/products/sync/": ["GET"] };
"/products/sync/": ["GET"]
};
if (env.NODE_ENV === "development" && skip[path]?.includes(request.method)) return; if (env.NODE_ENV === "development" && skip[path]?.includes(request.method)) return;
log.info({ log.info({
@@ -165,16 +163,12 @@ export const app = new Elysia()
state: await productSyncer.getState(), state: await productSyncer.getState(),
isRunning: await productSyncer.isRunning() isRunning: await productSyncer.isRunning()
})) }))
// Full sync // Run sync
.post("/", async ({ }) => { .post("/:printfulProductId?", async ({ params: { printfulProductId } }) => {
if (!await productSyncer.sync()) log.debug({ printfulProductId });
throw status(409, "Sync already in progress"); const canSync = await productSyncer.sync({ filter: { printfulProductIds: printfulProductId } });
}) if (!canSync) throw status(409, "Sync already in progress");
// Per-product sync }, { params: t.Object({ printfulProductId: t.Optional(t.Numeric()) }) }),
.post("/:printfulProductId", async ({ params }) => {
if (!await productSyncer.sync({ printfulProductIdsFilter: [params.printfulProductId] }))
throw status(409, "Sync already in progress");
}, { params: t.Object({ printfulProductId: t.Numeric() }) }),
) )
.get("/:printfulProductId", async ({ params }) => { .get("/:printfulProductId", async ({ params }) => {
const printfulProduct = await printful.Products.get(params.printfulProductId); const printfulProduct = await printful.Products.get(params.printfulProductId);
@@ -200,7 +194,7 @@ export const app = new Elysia()
case Printful.Webhook.Event.ProductUpdated: { case Printful.Webhook.Event.ProductUpdated: {
const printfulProduct = payload.data.sync_product; const printfulProduct = payload.data.sync_product;
log.info({ productId: printfulProduct.id }, "printful webhook: product updated"); log.info({ productId: printfulProduct.id }, "printful webhook: product updated");
await productSyncer.sync({ printfulProductIdsFilter: [printfulProduct.id] }); await productSyncer.sync({ filter: { printfulProductIds: printfulProduct.id } });
break; break;
} }
case Printful.Webhook.Event.ProductDeleted: { case Printful.Webhook.Event.ProductDeleted: {
@@ -28,7 +28,7 @@
}, },
sync: async (printfulProductId: number) => { sync: async (printfulProductId: number) => {
synchronizer.startPolling(); synchronizer.startPolling();
await api.products.sync.post({ printfulProductId }); await api.products.sync({ printfulProductId }).post();
}, },
}); });
+15 -7
View File
@@ -23,7 +23,9 @@ type SyncState = {
}; };
type SyncOptions = { type SyncOptions = {
printfulProductIdsFilter?: number[]; filter?: {
printfulProductIds?: number[] | number;
}
}; };
export class ProductSyncer { export class ProductSyncer {
@@ -38,14 +40,17 @@ export class ProductSyncer {
} }
async sync(opt: SyncOptions = {}): Promise<boolean> { async sync(opt: SyncOptions = {}): Promise<boolean> {
if (typeof opt.filter?.printfulProductIds === "number")
opt.filter.printfulProductIds = [opt.filter.printfulProductIds];
this.log.info("attempting sync run"); this.log.info("attempting sync run");
const canRun = await this.run(); const canRun = await this.run();
if (!canRun) return false; if (!canRun) return false;
try { try {
const syncStart = Date.now(); const syncStart = Date.now();
if (opt.printfulProductIdsFilter) if (opt.filter?.printfulProductIds)
this.log.info({ printfulProductIds: opt.printfulProductIdsFilter }, "sync started (filtered)"); this.log.info({ printfulProductIds: opt.filter.printfulProductIds }, "sync started (filtered)");
else else
this.log.info("sync started (all)"); this.log.info("sync started (all)");
@@ -55,8 +60,8 @@ export class ProductSyncer {
this.log.debug("retrieving printful products"); this.log.debug("retrieving printful products");
const allPrintfulProducts = await this.printful.Products.list({ forceAll: true }); const allPrintfulProducts = await this.printful.Products.list({ forceAll: true });
this.log.info({ printfulProductCount: allPrintfulProducts.length, filter: opt.printfulProductIdsFilter ?? "N/A" }, "generating meta printful products"); this.log.info({ printfulProductCount: allPrintfulProducts.length, filter: opt.filter ?? "N/A" }, "generating meta printful products");
const metaPrintfulProducts = await this.generateMetaPrintfulProducts(allWebflowProducts, allPrintfulProducts, opt.printfulProductIdsFilter); const metaPrintfulProducts = await this.generateMetaPrintfulProducts(allWebflowProducts, allPrintfulProducts, opt);
for (const metaPrintfulProduct of metaPrintfulProducts) { for (const metaPrintfulProduct of metaPrintfulProducts) {
this.log.info({ name: metaPrintfulProduct.name, externalId: metaPrintfulProduct.webflowProductId }, "syncing meta printful product"); this.log.info({ name: metaPrintfulProduct.name, externalId: metaPrintfulProduct.webflowProductId }, "syncing meta printful product");
@@ -266,9 +271,12 @@ export class ProductSyncer {
async generateMetaPrintfulProducts( async generateMetaPrintfulProducts(
allWebflowProducts: Webflow.Products.ProductAndSkus[], allWebflowProducts: Webflow.Products.ProductAndSkus[],
allPrintfulProducts: Printful.Products.SyncProduct[], allPrintfulProducts: Printful.Products.SyncProduct[],
printfulProductIdsFilter?: number[], opt: SyncOptions,
) { ) {
const metaNameFilter = printfulProductIdsFilter if (typeof opt.filter?.printfulProductIds === "number")
opt.filter.printfulProductIds = [opt.filter.printfulProductIds];
const metaNameFilter = opt.filter?.printfulProductIds
?.map((id) => allPrintfulProducts.find((p) => p.id === id)) ?.map((id) => allPrintfulProducts.find((p) => p.id === id))
?.filter((p) => p !== undefined) ?.filter((p) => p !== undefined)
?.map((p) => this.getMetaPrintfulProductName(p)); ?.map((p) => this.getMetaPrintfulProductName(p));