perf(cleaner-history): parallelize batch fetching in searchBatches
Replace sequential for-loop with Promise.all so that matched batches are fetched concurrently instead of one-by-one, reducing total query latency from O(n) serial round-trips to a single parallel batch. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1068,63 +1068,66 @@ export class CleanerOperationHistoryDAO {
|
|||||||
return { batches: [], totalMatches: 0 }
|
return { batches: [], totalMatches: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch full nested data for each matched batch
|
// Fetch full nested data for each matched batch (parallel)
|
||||||
const batches: CleanerSearchBatchResult[] = []
|
const batchResults = await Promise.all(
|
||||||
|
limitedBatchIds.map(async (batchId) => {
|
||||||
|
try {
|
||||||
|
const details = await this.getBatchDetails(batchId)
|
||||||
|
|
||||||
for (const batchId of limitedBatchIds) {
|
if (details.executions.length === 0) {
|
||||||
try {
|
return null
|
||||||
const details = await this.getBatchDetails(batchId)
|
}
|
||||||
|
|
||||||
if (details.executions.length === 0) {
|
// Derive batch stats from execution records
|
||||||
continue
|
const latestExec = details.executions.reduce((a, b) =>
|
||||||
}
|
a.attemptNumber > b.attemptNumber ? a : b
|
||||||
|
)
|
||||||
|
|
||||||
// Derive batch stats from execution records
|
const batch: CleanerBatchStats = {
|
||||||
const latestExec = details.executions.reduce((a, b) =>
|
batchId,
|
||||||
a.attemptNumber > b.attemptNumber ? a : b
|
userId: latestExec.userId,
|
||||||
)
|
username: latestExec.username,
|
||||||
|
operationTime: latestExec.operationTime.toISOString(),
|
||||||
|
status: latestExec.status,
|
||||||
|
totalAttempts: details.executions.length,
|
||||||
|
totalOrders: latestExec.totalOrders,
|
||||||
|
ordersProcessed: latestExec.ordersProcessed,
|
||||||
|
totalMaterialsDeleted: latestExec.totalMaterialsDeleted,
|
||||||
|
totalMaterialsFailed: latestExec.totalMaterialsFailed,
|
||||||
|
successCount: details.orders.filter((o) => o.status === 'success').length,
|
||||||
|
failedCount: details.orders.filter((o) => o.status === 'failed').length,
|
||||||
|
isDryRun: latestExec.isDryRun
|
||||||
|
}
|
||||||
|
|
||||||
const batch: CleanerBatchStats = {
|
// Fetch materials for each order
|
||||||
batchId,
|
const ordersWithMaterials = await Promise.all(
|
||||||
userId: latestExec.userId,
|
details.orders.map(async (order) => {
|
||||||
username: latestExec.username,
|
const materials = await this.getMaterialDetails(
|
||||||
operationTime: latestExec.operationTime.toISOString(),
|
batchId,
|
||||||
status: latestExec.status,
|
order.attemptNumber,
|
||||||
totalAttempts: details.executions.length,
|
order.orderNumber
|
||||||
totalOrders: latestExec.totalOrders,
|
)
|
||||||
ordersProcessed: latestExec.ordersProcessed,
|
return { order, materials }
|
||||||
totalMaterialsDeleted: latestExec.totalMaterialsDeleted,
|
})
|
||||||
totalMaterialsFailed: latestExec.totalMaterialsFailed,
|
)
|
||||||
successCount: details.orders.filter((o) => o.status === 'success').length,
|
|
||||||
failedCount: details.orders.filter((o) => o.status === 'failed').length,
|
|
||||||
isDryRun: latestExec.isDryRun
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch materials for each order
|
return {
|
||||||
const ordersWithMaterials = await Promise.all(
|
batch,
|
||||||
details.orders.map(async (order) => {
|
executions: details.executions,
|
||||||
const materials = await this.getMaterialDetails(
|
orders: ordersWithMaterials
|
||||||
batchId,
|
} satisfies CleanerSearchBatchResult
|
||||||
order.attemptNumber,
|
} catch (error) {
|
||||||
order.orderNumber
|
log.error('Error fetching batch data for search result', {
|
||||||
)
|
operationType: 'SELECT',
|
||||||
return { order, materials }
|
batchId,
|
||||||
|
error: error instanceof Error ? error.message : String(error)
|
||||||
})
|
})
|
||||||
)
|
return null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
batches.push({
|
const batches = batchResults.filter((r): r is CleanerSearchBatchResult => r !== null)
|
||||||
batch,
|
|
||||||
executions: details.executions,
|
|
||||||
orders: ordersWithMaterials
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
log.error('Error fetching batch data for search result', {
|
|
||||||
operationType: 'SELECT',
|
|
||||||
batchId,
|
|
||||||
error: error instanceof Error ? error.message : String(error)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info('Search batches completed', {
|
log.info('Search batches completed', {
|
||||||
operationType: 'SELECT',
|
operationType: 'SELECT',
|
||||||
|
|||||||
Reference in New Issue
Block a user