perf: prevent import hanging with timeouts and batching
- verifyAndFixInteractionModesCount: paginated DB queries (500/batch) instead of loading all items into memory at once - withFurniDataLock: add 60s chain timeout to prevent deadlocks when a lock holder stalls or crashes - withGamedataLock: same timeout protection for gamedata locks - conversion-pool: add 60s per-job timeout, fall back to main thread - furni/batch: abort signal + post_import progress events + skip post-import steps when client disconnects - furni/batch-regen: abort signal + early exit when disconnected - clone/sync-all: pre-fetch furnidata once per source instead of per item (eliminates 2000+ redundant fetches) - sse-client: add 60s idle timeout to prevent infinite hangs
This commit is contained in:
1 parent
f70d96b81c
commit
7556b1f3fa
5 files changed
+222
-93
No files matched your search
@@ -1128,83 +1128,84 @@ export async function verifyAndFixInteractionModesCount(): Promise<{
|
||||
let fixed = 0;
|
||||
let checked = 0;
|
||||
let skipped = 0;
|
||||
const BATCH_SIZE = 500;
|
||||
|
||||
try {
|
||||
const allItems = await db
|
||||
.select({
|
||||
id: ItemsBase.id,
|
||||
itemName: ItemsBase.itemName,
|
||||
publicName: ItemsBase.publicName,
|
||||
allowSit: ItemsBase.allowSit,
|
||||
allowLay: ItemsBase.allowLay,
|
||||
allowWalk: ItemsBase.allowWalk,
|
||||
interactionType: ItemsBase.interactionType,
|
||||
interactionModesCount: ItemsBase.interactionModesCount,
|
||||
})
|
||||
.from(ItemsBase);
|
||||
let offset = 0;
|
||||
while (true) {
|
||||
const batch = await db
|
||||
.select({
|
||||
id: ItemsBase.id,
|
||||
itemName: ItemsBase.itemName,
|
||||
publicName: ItemsBase.publicName,
|
||||
allowSit: ItemsBase.allowSit,
|
||||
allowLay: ItemsBase.allowLay,
|
||||
allowWalk: ItemsBase.allowWalk,
|
||||
interactionType: ItemsBase.interactionType,
|
||||
interactionModesCount: ItemsBase.interactionModesCount,
|
||||
})
|
||||
.from(ItemsBase)
|
||||
.limit(BATCH_SIZE)
|
||||
.offset(offset);
|
||||
|
||||
for (const item of allItems) {
|
||||
checked++;
|
||||
const realFlags = await lookupRealFurniFlags(item.itemName);
|
||||
if (batch.length === 0) break;
|
||||
offset += batch.length;
|
||||
checked += batch.length;
|
||||
|
||||
// Real data absent → do not guess, leave the item untouched.
|
||||
if (realFlags.source === "none") {
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
for (const item of batch) {
|
||||
const realFlags = await lookupRealFurniFlags(item.itemName);
|
||||
|
||||
const animationModes = await realNitroModes(item.itemName);
|
||||
const auto = autoDetectInteraction(item.itemName, item.publicName, {
|
||||
cansiton: realFlags.cansiton,
|
||||
canlayon: realFlags.canlayon,
|
||||
canstandon: realFlags.canstandon,
|
||||
// Furnidata flags are curated → authoritative over keywords.
|
||||
hasActionData: true,
|
||||
animationStates: animationModes,
|
||||
});
|
||||
if (realFlags.source === "none") {
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const changes: Partial<Record<string, unknown>> = {};
|
||||
// allow_sit/lay/walk of 2 is emulator-special (e.g. tents lay=2,
|
||||
// walk-through walk=2) — never overwrite those with a 0/1.
|
||||
if (
|
||||
item.allowSit !== 2 &&
|
||||
(item.allowSit ? 1 : 0) !== (auto.canSit ? 1 : 0)
|
||||
)
|
||||
changes.allowSit = auto.canSit ? 1 : 0;
|
||||
if (
|
||||
item.allowLay !== 2 &&
|
||||
(item.allowLay ? 1 : 0) !== (auto.canLay ? 1 : 0)
|
||||
)
|
||||
changes.allowLay = auto.canLay ? 1 : 0;
|
||||
if (
|
||||
item.allowWalk !== 2 &&
|
||||
(item.allowWalk ? 1 : 0) !== (auto.canStand ? 1 : 0)
|
||||
)
|
||||
changes.allowWalk = auto.canStand ? 1 : 0;
|
||||
if ((item.interactionModesCount ?? 0) !== auto.interactionModesCount)
|
||||
changes.interactionModesCount = auto.interactionModesCount;
|
||||
// Only fill interaction_type when the DB still has the generic
|
||||
// "default" (nothing emulator-specific configured). Never overwrite
|
||||
// an existing handler type (e.g. intelligence_bookcase, nest, wf_*)
|
||||
// — those are emulator semantics that real furnidata cannot replace.
|
||||
if (
|
||||
(item.interactionType === "default" || !item.interactionType) &&
|
||||
auto.interactionType !== "default"
|
||||
) {
|
||||
changes.interactionType = auto.interactionType;
|
||||
}
|
||||
const animationModes = await realNitroModes(item.itemName);
|
||||
const auto = autoDetectInteraction(item.itemName, item.publicName, {
|
||||
cansiton: realFlags.cansiton,
|
||||
canlayon: realFlags.canlayon,
|
||||
canstandon: realFlags.canstandon,
|
||||
hasActionData: true,
|
||||
animationStates: animationModes,
|
||||
});
|
||||
|
||||
if (Object.keys(changes).length > 0) {
|
||||
try {
|
||||
await db
|
||||
.update(ItemsBase)
|
||||
.set(changes)
|
||||
.where(eq(ItemsBase.id, item.id));
|
||||
fixed++;
|
||||
} catch (err) {
|
||||
errors.push(
|
||||
`Failed to fix ${item.itemName}: ${(err as Error).message}`,
|
||||
);
|
||||
const changes: Partial<Record<string, unknown>> = {};
|
||||
if (
|
||||
item.allowSit !== 2 &&
|
||||
(item.allowSit ? 1 : 0) !== (auto.canSit ? 1 : 0)
|
||||
)
|
||||
changes.allowSit = auto.canSit ? 1 : 0;
|
||||
if (
|
||||
item.allowLay !== 2 &&
|
||||
(item.allowLay ? 1 : 0) !== (auto.canLay ? 1 : 0)
|
||||
)
|
||||
changes.allowLay = auto.canLay ? 1 : 0;
|
||||
if (
|
||||
item.allowWalk !== 2 &&
|
||||
(item.allowWalk ? 1 : 0) !== (auto.canStand ? 1 : 0)
|
||||
)
|
||||
changes.allowWalk = auto.canStand ? 1 : 0;
|
||||
if ((item.interactionModesCount ?? 0) !== auto.interactionModesCount)
|
||||
changes.interactionModesCount = auto.interactionModesCount;
|
||||
if (
|
||||
(item.interactionType === "default" || !item.interactionType) &&
|
||||
auto.interactionType !== "default"
|
||||
) {
|
||||
changes.interactionType = auto.interactionType;
|
||||
}
|
||||
|
||||
if (Object.keys(changes).length > 0) {
|
||||
try {
|
||||
await db
|
||||
.update(ItemsBase)
|
||||
.set(changes)
|
||||
.where(eq(ItemsBase.id, item.id));
|
||||
fixed++;
|
||||
} catch (err) {
|
||||
errors.push(
|
||||
`Failed to fix ${item.itemName}: ${(err as Error).message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user