Montify sync: save progress every 5 customers; skip endpoints returning 404, summarize instead of per-customer errors
This commit is contained in:
@@ -37,6 +37,10 @@ import {
|
||||
|
||||
const CUSTOMER_PAGE_SIZE = 50;
|
||||
const ENGAGEMENT_KEEP = 50;
|
||||
/** مسیری که پشتسرهم 404 بدهد (پیاده نشده) تا پایان همان دور رد میشود */
|
||||
const SKIP_AFTER_NOT_FOUND = 3;
|
||||
|
||||
type EndpointStats = Map<string, { ok: number; notFound: number }>;
|
||||
|
||||
/** پروفایل فروشگاهی مشتری (MontifyLink.data) — نامها طبق جدول نگاشت مستند */
|
||||
type CustomerProfile = {
|
||||
@@ -221,6 +225,7 @@ export class MontifySyncService {
|
||||
onStarted?.();
|
||||
}
|
||||
|
||||
const endpoints: EndpointStats = new Map();
|
||||
let cursor = row.customersCursor;
|
||||
let fatal: string | null = null;
|
||||
try {
|
||||
@@ -234,10 +239,10 @@ export class MontifySyncService {
|
||||
do {
|
||||
const res = await client.listCustomers({ page, limit: CUSTOMER_PAGE_SIZE, updatedAfter });
|
||||
lastPage = res.meta.last_page;
|
||||
result.customersFetched += res.data.length;
|
||||
for (const customer of res.data) {
|
||||
result.customersFetched += 1;
|
||||
try {
|
||||
const outcome = await this.syncCustomerDeep(row, client, customer, mode, result);
|
||||
const outcome = await this.syncCustomerDeep(row, client, customer, mode, result, endpoints);
|
||||
if (outcome === 'created') result.customersCreated += 1;
|
||||
else result.customersUpdated += 1;
|
||||
const updatedAt = parseDate(customer.updated_at);
|
||||
@@ -248,6 +253,7 @@ export class MontifySyncService {
|
||||
result.errors.push(`مشتری ${customer.id}: ${msg}`);
|
||||
this.logger.warn(`Montify ${row.id} customer ${customer.id}: ${msg}`);
|
||||
}
|
||||
if (result.customersFetched % 5 === 0) await saveProgress();
|
||||
}
|
||||
await saveProgress();
|
||||
if (!res.data.length) break;
|
||||
@@ -261,8 +267,15 @@ export class MontifySyncService {
|
||||
this.running.delete(row.id);
|
||||
}
|
||||
|
||||
const missing = [...endpoints.entries()]
|
||||
.filter(([, s]) => s.notFound > 0)
|
||||
.map(
|
||||
([label, s]) =>
|
||||
`مسیر ${label}: ${s.notFound} بار 404 داد` +
|
||||
(s.ok ? '' : ' (احتمالاً در این فروشگاه پیاده نشده)'),
|
||||
);
|
||||
result.finishedAt = new Date().toISOString();
|
||||
result.errors = result.errors.slice(0, 50);
|
||||
result.errors = [...missing, ...result.errors].slice(0, 50);
|
||||
await this.prisma.montifyConnection.update({
|
||||
where: { id: row.id },
|
||||
data: {
|
||||
@@ -291,13 +304,23 @@ export class MontifySyncService {
|
||||
customer: MontifyCustomer,
|
||||
mode: 'incremental' | 'full',
|
||||
result: MontifySyncResultDto | null,
|
||||
endpoints: EndpointStats = new Map(),
|
||||
): Promise<'created' | 'updated'> {
|
||||
const externalId = String(customer.id);
|
||||
const step = async <T>(label: string, fn: () => Promise<T>): Promise<T | null> => {
|
||||
const stats = endpoints.get(label) ?? { ok: 0, notFound: 0 };
|
||||
endpoints.set(label, stats);
|
||||
if (stats.ok === 0 && stats.notFound >= SKIP_AFTER_NOT_FOUND) return null;
|
||||
try {
|
||||
return await fn();
|
||||
const value = await fn();
|
||||
stats.ok += 1;
|
||||
return value;
|
||||
} catch (e) {
|
||||
if (e instanceof MontifyHttpError && e.status === 401) throw e;
|
||||
if (e instanceof MontifyHttpError && e.status === 404) {
|
||||
stats.notFound += 1;
|
||||
return null;
|
||||
}
|
||||
const msg = e instanceof Error ? e.message : String(e);
|
||||
result?.errors.push(`مشتری ${externalId} (${label}): ${msg}`);
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user