mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-03-29 11:57:20 +02:00
🐛 fix: Resolve MeiliSearch Startup Sync Failure from Model Loading Order (#12397)
* fix: resolve MeiliSearch startup sync failure from model loading order `indexSync.js` captures `mongoose.models.Message` and `mongoose.models.Conversation` at module load time (lines 9-10). Since PR #11830 moved model registration into `createModels()`, these references are always `undefined` because `require('./indexSync')` ran before `createModels(mongoose)` in `api/db/index.js`. Move the `require('./indexSync')` below `createModels(mongoose)` so Mongoose models are registered before `indexSync.js` captures them. * fix: defer model lookups in indexSync, add load-order regression test - Move mongoose.models.Message and mongoose.models.Conversation lookups from module-level into performSync() and the indexSync() catch block, eliminating the fragile load-order dependency that caused the original regression - Add guard assertion that throws a clear error if models are missing - Add comment in api/db/index.js documenting the createModels ordering constraint - Add api/db/index.spec.js regression test to prevent future re-introduction of the load-order bug * fix: strengthen regression test to verify call order, add guard in setTimeout path - Rewrite index.spec.js to track call sequence via callOrder array, ensuring createModels executes before indexSync module loads (verified: test fails if order is reversed) - Add missing model guard assertion in the setTimeout fallback path in indexSync.js for consistency with performSync --------- Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
parent
734239346b
commit
6466483ae3
3 changed files with 47 additions and 4 deletions
|
|
@ -1,8 +1,13 @@
|
|||
const mongoose = require('mongoose');
|
||||
const { createModels } = require('@librechat/data-schemas');
|
||||
const { connectDb } = require('./connect');
|
||||
const indexSync = require('./indexSync');
|
||||
|
||||
// createModels MUST run before requiring indexSync.
|
||||
// indexSync.js captures mongoose.models.Message and mongoose.models.Conversation
|
||||
// at module load time. If those models are not registered first, all MeiliSearch
|
||||
// sync operations will silently fail on every startup.
|
||||
createModels(mongoose);
|
||||
|
||||
const indexSync = require('./indexSync');
|
||||
|
||||
module.exports = { connectDb, indexSync };
|
||||
|
|
|
|||
26
api/db/index.spec.js
Normal file
26
api/db/index.spec.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
describe('api/db/index.js', () => {
|
||||
test('createModels is called before indexSync is loaded', () => {
|
||||
jest.resetModules();
|
||||
|
||||
const callOrder = [];
|
||||
|
||||
jest.mock('@librechat/data-schemas', () => ({
|
||||
createModels: jest.fn((m) => {
|
||||
callOrder.push('createModels');
|
||||
m.models.Message = { name: 'Message' };
|
||||
m.models.Conversation = { name: 'Conversation' };
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('./indexSync', () => {
|
||||
callOrder.push('indexSync');
|
||||
return jest.fn();
|
||||
});
|
||||
|
||||
jest.mock('./connect', () => ({ connectDb: jest.fn() }));
|
||||
|
||||
require('./index');
|
||||
|
||||
expect(callOrder).toEqual(['createModels', 'indexSync']);
|
||||
});
|
||||
});
|
||||
|
|
@ -6,9 +6,6 @@ const { isEnabled, FlowStateManager } = require('@librechat/api');
|
|||
const { getLogStores } = require('~/cache');
|
||||
const { batchResetMeiliFlags } = require('./utils');
|
||||
|
||||
const Conversation = mongoose.models.Conversation;
|
||||
const Message = mongoose.models.Message;
|
||||
|
||||
const searchEnabled = isEnabled(process.env.SEARCH);
|
||||
const indexingDisabled = isEnabled(process.env.MEILI_NO_SYNC);
|
||||
let currentTimeout = null;
|
||||
|
|
@ -200,6 +197,14 @@ async function performSync(flowManager, flowId, flowType) {
|
|||
return { messagesSync: false, convosSync: false };
|
||||
}
|
||||
|
||||
const Message = mongoose.models.Message;
|
||||
const Conversation = mongoose.models.Conversation;
|
||||
if (!Message || !Conversation) {
|
||||
throw new Error(
|
||||
'[indexSync] Models not registered. Ensure createModels() has been called before indexSync.',
|
||||
);
|
||||
}
|
||||
|
||||
const client = MeiliSearchClient.getInstance();
|
||||
|
||||
const { status } = await client.health();
|
||||
|
|
@ -349,6 +354,13 @@ async function indexSync() {
|
|||
logger.debug('[indexSync] Creating indices...');
|
||||
currentTimeout = setTimeout(async () => {
|
||||
try {
|
||||
const Message = mongoose.models.Message;
|
||||
const Conversation = mongoose.models.Conversation;
|
||||
if (!Message || !Conversation) {
|
||||
throw new Error(
|
||||
'[indexSync] Models not registered. Ensure createModels() has been called before indexSync.',
|
||||
);
|
||||
}
|
||||
await Message.syncWithMeili();
|
||||
await Conversation.syncWithMeili();
|
||||
} catch (err) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue