mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-11 21:18:51 +01:00
🔧 refactor: batching documents on meili index reset (#11165)
* 🔧 refactor: batching documents on meili index reset Update on all documents can be very heavy on weak or low-tier instances 🔧 refactor: check if flag is enabled before calling meilisearch 🔧 fix: adding index to query documents to reset meili-search index status * 🔧 refactor: error handling 🔧 refactor: more unit-test coverage * 🔧 refactor: edge case error handling & tests
This commit is contained in:
parent
791dab8f20
commit
7d136edb40
6 changed files with 648 additions and 24 deletions
90
api/db/utils.js
Normal file
90
api/db/utils.js
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
const { logger } = require('@librechat/data-schemas');
|
||||
|
||||
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
/**
|
||||
* Batch update documents in chunks to avoid timeouts on weak instances
|
||||
* @param {mongoose.Collection} collection - MongoDB collection
|
||||
* @returns {Promise<number>} - Total modified count
|
||||
* @throws {Error} - Throws if database operations fail (e.g., network issues, connection loss, permission problems)
|
||||
*/
|
||||
async function batchResetMeiliFlags(collection) {
|
||||
const DEFAULT_BATCH_SIZE = 1000;
|
||||
|
||||
let BATCH_SIZE = parseEnvInt('MEILI_SYNC_BATCH_SIZE', DEFAULT_BATCH_SIZE);
|
||||
if (BATCH_SIZE === 0) {
|
||||
logger.warn(
|
||||
`[batchResetMeiliFlags] MEILI_SYNC_BATCH_SIZE cannot be 0. Using default: ${DEFAULT_BATCH_SIZE}`,
|
||||
);
|
||||
BATCH_SIZE = DEFAULT_BATCH_SIZE;
|
||||
}
|
||||
|
||||
const BATCH_DELAY_MS = parseEnvInt('MEILI_SYNC_DELAY_MS', 100);
|
||||
let totalModified = 0;
|
||||
let hasMore = true;
|
||||
|
||||
try {
|
||||
while (hasMore) {
|
||||
const docs = await collection
|
||||
.find({ expiredAt: null, _meiliIndex: true }, { projection: { _id: 1 } })
|
||||
.limit(BATCH_SIZE)
|
||||
.toArray();
|
||||
|
||||
if (docs.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
const ids = docs.map((doc) => doc._id);
|
||||
const result = await collection.updateMany(
|
||||
{ _id: { $in: ids } },
|
||||
{ $set: { _meiliIndex: false } },
|
||||
);
|
||||
|
||||
totalModified += result.modifiedCount;
|
||||
process.stdout.write(
|
||||
`\r Updating ${collection.collectionName}: ${totalModified} documents...`,
|
||||
);
|
||||
|
||||
if (docs.length < BATCH_SIZE) {
|
||||
hasMore = false;
|
||||
}
|
||||
|
||||
if (hasMore && BATCH_DELAY_MS > 0) {
|
||||
await sleep(BATCH_DELAY_MS);
|
||||
}
|
||||
}
|
||||
|
||||
return totalModified;
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to batch reset Meili flags for collection '${collection.collectionName}' after processing ${totalModified} documents: ${error.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and validate an environment variable as a positive integer
|
||||
* @param {string} varName - Environment variable name
|
||||
* @param {number} defaultValue - Default value to use if invalid or missing
|
||||
* @returns {number} - Parsed value or default
|
||||
*/
|
||||
function parseEnvInt(varName, defaultValue) {
|
||||
const value = process.env[varName];
|
||||
if (!value) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
const parsed = parseInt(value, 10);
|
||||
if (isNaN(parsed) || parsed < 0) {
|
||||
logger.warn(
|
||||
`[batchResetMeiliFlags] Invalid value for ${varName}="${value}". Expected a positive integer. Using default: ${defaultValue}`,
|
||||
);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
batchResetMeiliFlags,
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue