Allow large activity Excel imports (40k+ rows) with bigger chunks and caches.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-03 17:42:11 +03:30
co-authored by Cursor
parent beae16437b
commit c629729a9a
4 changed files with 96 additions and 22 deletions
+33 -1
View File
@@ -1,16 +1,24 @@
import { randomBytes } from 'node:crypto';
import { BadRequestException } from '@nestjs/common';
export const EXCEL_IMPORT_CHUNK_SIZE = 80;
export const EXCEL_IMPORT_CHUNK_SIZE = 150;
/** بعد از این تعداد ردیف، کلاینت حتماً چندمرحله‌ای می‌رود (پیش‌نمایش هم نشان می‌دهد) */
export const EXCEL_IMPORT_LARGE_THRESHOLD = 80;
const SESSION_TTL_MS = 45 * 60 * 1000;
const MAX_SESSIONS = 40;
export type ExcelImportLookupCaches = {
user: Map<string, string | null>;
person: Map<string, string | null>;
company: Map<string, string | null>;
deal: Map<string, string | null>;
};
type ExcelImportSession = {
organizationId: string;
rows: Array<Record<string, string>>;
expiresAt: number;
caches: ExcelImportLookupCaches;
};
const sessions = new Map<string, ExcelImportSession>();
@@ -40,6 +48,12 @@ export function createExcelImportSession(
organizationId,
rows,
expiresAt: Date.now() + SESSION_TTL_MS,
caches: {
user: new Map(),
person: new Map(),
company: new Map(),
deal: new Map(),
},
});
return id;
}
@@ -64,6 +78,24 @@ export function destroyExcelImportSession(sessionId: string | undefined) {
sessions.delete(sessionId);
}
export function getExcelImportSessionCaches(
sessionId: string,
organizationId: string,
): ExcelImportLookupCaches {
purgeExpired();
const session = sessions.get(sessionId);
if (!session || session.organizationId !== organizationId) {
return {
user: new Map(),
person: new Map(),
company: new Map(),
deal: new Map(),
};
}
session.expiresAt = Date.now() + SESSION_TTL_MS;
return session.caches;
}
export function parseChunkParams(raw: {
offset?: string | number;
limit?: string | number;
+2 -10
View File
@@ -319,16 +319,8 @@ export async function previewExcel(
const missingRequired = required.some((key) => !mapped.has(key));
const unrecognized = columns.some((col) => !suggested[col.header]);
let rowCount = 0;
sheet.eachRow((row, rowNumber) => {
if (rowNumber === 1) return;
let any = false;
row.eachCell((cell) => {
if (any) return;
if (cellStr(cell.value)) any = true;
});
if (any) rowCount += 1;
});
// برای فایل‌های خیلی بزرگ (ده‌ها هزار ردیف) پیمایش کامل کند است؛ rowCount شیت کافی است
const rowCount = Math.max(0, (sheet.actualRowCount || sheet.rowCount || 1) - 1);
return {
columns,