fix: reduce import concurrency to prevent 100% CPU during SWF→Nitro conversion
- Default batch concurrency: 3→1 (max 5→3) - Default batch-regen concurrency: 3→1 (max 5→3) - Default IMPORT_BATCH_CONCURRENCY: 12→3 - Added setImmediate yields between items to prevent event loop blocking Fixes gatje and other complex furniture imports consuming 100% CPU and stalling the catalog studio.
This commit is contained in:
1 parent
c043af318b
commit
c2e61dc324
3 files changed
+7
-3
No files matched your search
@@ -39,7 +39,7 @@ export const POST = withAdmin(
|
|||||||
async (request) => {
|
async (request) => {
|
||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
const items: RegenItem[] = body.items || [];
|
const items: RegenItem[] = body.items || [];
|
||||||
const concurrency = Math.min(Math.max(body.concurrency || 3, 1), 5);
|
const concurrency = Math.min(Math.max(body.concurrency || 1, 1), 3);
|
||||||
|
|
||||||
if (items.length === 0) return apiError("No items to regenerate", 400);
|
if (items.length === 0) return apiError("No items to regenerate", 400);
|
||||||
|
|
||||||
@@ -237,6 +237,7 @@ export const POST = withAdmin(
|
|||||||
});
|
});
|
||||||
|
|
||||||
await Promise.allSettled(promises);
|
await Promise.allSettled(promises);
|
||||||
|
await new Promise((r) => setImmediate(r));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Batch write FurnitureData.json
|
// Batch write FurnitureData.json
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export const POST = withAdmin(
|
|||||||
async (request, ctx) => {
|
async (request, ctx) => {
|
||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
const rawItems: BatchItem[] = body.items || [];
|
const rawItems: BatchItem[] = body.items || [];
|
||||||
const concurrency = Math.min(Math.max(body.concurrency || 3, 1), 5);
|
const concurrency = Math.min(Math.max(body.concurrency || 1, 1), 3);
|
||||||
const sourceId: string | undefined = body.sourceId;
|
const sourceId: string | undefined = body.sourceId;
|
||||||
|
|
||||||
if (rawItems.length === 0) return apiError("No items to import", 400);
|
if (rawItems.length === 0) return apiError("No items to import", 400);
|
||||||
@@ -179,6 +179,7 @@ export const POST = withAdmin(
|
|||||||
});
|
});
|
||||||
|
|
||||||
await Promise.allSettled(promises);
|
await Promise.allSettled(promises);
|
||||||
|
await new Promise((r) => setImmediate(r));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Batch write FurnitureData.json once at the end — BEFORE RCON so the
|
// Batch write FurnitureData.json once at the end — BEFORE RCON so the
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ import type { ImportSingleResult } from "@/types/furni";
|
|||||||
// How many items to import concurrently in a batch. The per-item work is
|
// How many items to import concurrently in a batch. The per-item work is
|
||||||
// network-bound (asset downloads) and DB-bound, so a modest pool gives a large
|
// network-bound (asset downloads) and DB-bound, so a modest pool gives a large
|
||||||
// speedup over the old fully sequential loop without overwhelming the DB.
|
// speedup over the old fully sequential loop without overwhelming the DB.
|
||||||
const IMPORT_BATCH_CONCURRENCY = 12;
|
const IMPORT_BATCH_CONCURRENCY = 3;
|
||||||
|
|
||||||
async function runWithConcurrency<T, R>(
|
async function runWithConcurrency<T, R>(
|
||||||
items: T[],
|
items: T[],
|
||||||
@@ -64,6 +64,7 @@ async function runWithConcurrency<T, R>(
|
|||||||
const i = cursor++;
|
const i = cursor++;
|
||||||
if (i >= items.length) break;
|
if (i >= items.length) break;
|
||||||
out[i] = await fn(items[i]);
|
out[i] = await fn(items[i]);
|
||||||
|
await new Promise((r) => setImmediate(r));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -849,6 +850,7 @@ export const PATCH = withAdmin(
|
|||||||
warning: (err as Error).message,
|
warning: (err as Error).message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
await new Promise((r) => setImmediate(r));
|
||||||
}
|
}
|
||||||
|
|
||||||
const succeeded = results.filter((r) => r.ok).length;
|
const succeeded = results.filter((r) => r.ok).length;
|
||||||
|
|||||||
Reference in new issue
Block a user