Fix redis race condition
This commit is contained in:
@@ -7,7 +7,7 @@ import pino from "pino";
|
||||
|
||||
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
type MainProduct = {
|
||||
type MetaPrintfulProduct = {
|
||||
name: string;
|
||||
externalId: string;
|
||||
colors: Set<string>;
|
||||
@@ -18,8 +18,7 @@ type MainProduct = {
|
||||
};
|
||||
|
||||
type SyncState = {
|
||||
isSyncing: boolean;
|
||||
syncingIds: number[];
|
||||
printfulProductIds: number[];
|
||||
};
|
||||
|
||||
export class ProductSyncer {
|
||||
@@ -33,14 +32,15 @@ export class ProductSyncer {
|
||||
this.log = (log ?? pino({ level: "silent" })).child({ component: "ProductSyncer" });
|
||||
}
|
||||
|
||||
async sync(printfulProductId?: number) {
|
||||
const syncStart = Date.now();
|
||||
async sync(printfulProductId?: number): Promise<boolean> {
|
||||
const canRun = await this.run();
|
||||
if (!canRun) return false;
|
||||
|
||||
try {
|
||||
const syncStart = Date.now();
|
||||
if (printfulProductId) this.log.info({ printfulProductId }, "sync started");
|
||||
else this.log.info("sync started");
|
||||
|
||||
await this.setState({ isSyncing: true, syncingIds: [] });
|
||||
|
||||
this.log.debug("populating webflow products");
|
||||
const webflowProducts: Webflow.Products.ProductAndSkus[] = await this.webflow.Products.list({ forceAll: true });
|
||||
|
||||
@@ -59,7 +59,7 @@ export class ProductSyncer {
|
||||
}
|
||||
|
||||
this.log.info({ count: printfulProducts.length }, "generating meta printful products");
|
||||
const metaPrintfulProducts: MainProduct[] = [];
|
||||
const metaPrintfulProducts: MetaPrintfulProduct[] = [];
|
||||
for (const printfulProduct of printfulProducts) {
|
||||
const mainProductName = this.getMainProductName(
|
||||
printfulProduct.name,
|
||||
@@ -93,8 +93,7 @@ export class ProductSyncer {
|
||||
for (const metaPrintfulProduct of metaPrintfulProducts) {
|
||||
this.log.info({ name: metaPrintfulProduct.name }, "syncing meta printful product");
|
||||
await this.setState({
|
||||
isSyncing: true,
|
||||
syncingIds: metaPrintfulProduct.variants.map(
|
||||
printfulProductIds: metaPrintfulProduct.variants.map(
|
||||
(v) => v.product.sync_product.id,
|
||||
),
|
||||
});
|
||||
@@ -291,22 +290,13 @@ export class ProductSyncer {
|
||||
this.log.info({ durationMs: Date.now() - syncStart }, "sync complete");
|
||||
} finally {
|
||||
try {
|
||||
await this.setState({ isSyncing: false, syncingIds: [] });
|
||||
await redis.del("commerce:sync:lock");
|
||||
await redis.del("commerce:sync:state");
|
||||
} catch {
|
||||
this.log.error("failed to reset sync state");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async setState(state: SyncState) {
|
||||
await redis.set("commerce:sync:state", JSON.stringify(state));
|
||||
await redis.expire("commerce:sync:state", 1800);
|
||||
}
|
||||
|
||||
async getState(): Promise<SyncState> {
|
||||
const val = await redis.get("commerce:sync:state");
|
||||
if (val) return JSON.parse(val);
|
||||
return { isSyncing: false, syncingIds: [] };
|
||||
return true;
|
||||
}
|
||||
|
||||
findColorInProductName(productName: string): string {
|
||||
@@ -322,4 +312,22 @@ export class ProductSyncer {
|
||||
return productName;
|
||||
}
|
||||
}
|
||||
|
||||
async isRunning(): Promise<boolean> {
|
||||
return !!await redis.get("commerce:sync:lock");
|
||||
}
|
||||
|
||||
async getState(): Promise<SyncState> {
|
||||
const val = await redis.get("commerce:sync:state");
|
||||
if (val) return JSON.parse(val);
|
||||
return { printfulProductIds: [] };
|
||||
}
|
||||
|
||||
private async setState(state: SyncState) {
|
||||
await redis.set("commerce:sync:state", JSON.stringify(state), "EX", 1800);
|
||||
}
|
||||
|
||||
private async run(): Promise<boolean> {
|
||||
return !!await redis.set("commerce:sync:lock", "1", "NX", "EX", "1800");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user