Keep product migrate from crashing the API on large image copies.

PM2 was restarting at 512MB while Sharp cached buffers, which returned 502 to the migrate UI after categories had already succeeded.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-30 15:02:40 +03:30
co-authored by Cursor
parent a5f2f8d63b
commit 73588db1c6
2 changed files with 144 additions and 123 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ module.exports = {
env: { env: {
NODE_ENV: 'production', NODE_ENV: 'production',
}, },
max_memory_restart: '512M', max_memory_restart: '2G',
time: true, time: true,
}, },
], ],
@@ -19,6 +19,11 @@ import { StorageService } from '../storage/storage.service';
import { PrismaService } from '../prisma/prisma.service'; import { PrismaService } from '../prisma/prisma.service';
import { MigrateFromOldEntity } from './dto/migrate-from-old.dto'; import { MigrateFromOldEntity } from './dto/migrate-from-old.dto';
// Legacy product images are large; Sharp's default cache plus PM2's 512MB cap
// was restarting the API mid-migrate (nginx 502, UI "Unable to migrate").
sharp.cache(false);
sharp.concurrency(1);
export type MigrateEntityCounts = { export type MigrateEntityCounts = {
created: number; created: number;
skipped: number; skipped: number;
@@ -2482,6 +2487,7 @@ export class LegacyMigrateService {
continue; continue;
} }
try {
const titleEn = const titleEn =
(row.name_en ?? '').trim() || (row.name ?? '').trim() || 'Product'; (row.name_en ?? '').trim() || (row.name ?? '').trim() || 'Product';
const nameFa = (row.name ?? '').trim() || null; const nameFa = (row.name ?? '').trim() || null;
@@ -2620,6 +2626,21 @@ export class LegacyMigrateService {
} }
created += 1; created += 1;
} catch (err) {
console.error(
`Legacy migrate: product old id ${row.id} failed`,
err instanceof Error ? err.message : err,
);
skipped += 1;
}
if ((index + 1) % 25 === 0) {
const rssMb = Math.round(process.memoryUsage().rss / 1024 / 1024);
console.log(
`Legacy migrate: products ${index + 1}/${products.length} created=${created} skipped=${skipped} rss=${rssMb}MB`,
);
await new Promise((resolve) => setImmediate(resolve));
}
} }
return { return {