Rust discount function (one automatic discount evaluating all offers in priority order, parity with the Odoo engine), React Router admin with Polaris, theme app extension and app proxy pages, webhooks incl. GDPR, managed-pricing limits, and a Docker Compose stack (Postgres + Caddy HTTPS) for a single VPS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
45 lines
1.7 KiB
TypeScript
45 lines
1.7 KiB
TypeScript
// Re-publishes a shop's configuration at every offer start/end boundary (brief §11.5).
|
|
// Every 30 s it claims shops whose nextSyncAt has passed (atomic update, safe with several app instances)
|
|
// and publishes them with the shop's offline token. The function's guard covers the seconds in between
|
|
// for offers that END (see extensions/bundle-discount/src/config.rs), so no discount outlives its offer.
|
|
import db from "../db.server";
|
|
import { unauthenticated } from "../shopify.server";
|
|
import { publishShop } from "./publish.server";
|
|
|
|
const TICK_MS = 30_000;
|
|
|
|
export async function runDueSyncs(now = new Date()) {
|
|
const due = await db.shop.findMany({
|
|
where: { uninstalledAt: null, nextSyncAt: { lte: now } },
|
|
select: { id: true, domain: true, nextSyncAt: true },
|
|
take: 50,
|
|
});
|
|
for (const shop of due) {
|
|
// claim: only one instance gets each boundary
|
|
const claimed = await db.shop.updateMany({
|
|
where: { id: shop.id, nextSyncAt: shop.nextSyncAt },
|
|
data: { nextSyncAt: new Date(now.getTime() + 5 * 60_000) }, // safety retry if this run dies
|
|
});
|
|
if (!claimed.count) continue;
|
|
try {
|
|
const { admin } = await unauthenticated.admin(shop.domain);
|
|
await publishShop(admin, shop.domain, new Date());
|
|
} catch (e) {
|
|
console.error(`[scheduler] publish failed for ${shop.domain}`, e);
|
|
}
|
|
}
|
|
}
|
|
|
|
declare global {
|
|
// eslint-disable-next-line no-var
|
|
var __bundleOffersScheduler: NodeJS.Timeout | undefined;
|
|
}
|
|
|
|
export function startScheduler() {
|
|
if (globalThis.__bundleOffersScheduler || process.env.DISABLE_SCHEDULER === "1") return;
|
|
globalThis.__bundleOffersScheduler = setInterval(() => {
|
|
runDueSyncs().catch((e) => console.error("[scheduler]", e));
|
|
}, TICK_MS);
|
|
globalThis.__bundleOffersScheduler.unref?.();
|
|
}
|