mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-03-29 03:47:18 +02:00
* feat: replace unsupported MongoDB aggregation operators for FerretDB compatibility Replace $lookup, $unwind, $sample, $replaceRoot, and $addFields aggregation stages which are unsupported on FerretDB v2.x (postgres-documentdb backend). - Prompt.js: Replace $lookup/$unwind/$project pipelines with find().select().lean() + attachProductionPrompts() batch helper. Replace $group/$replaceRoot/$sample in getRandomPromptGroups with distinct() + Fisher-Yates shuffle. - Agent/Prompt migration scripts: Replace $lookup anti-join pattern with distinct() + $nin two-step queries for finding un-migrated resources. All replacement patterns verified against FerretDB v2.7.0. * fix: use $pullAll for simple array removals, fix memberIds type mismatches Replace $pull with $pullAll for exact-value scalar array removals. Both operators work on MongoDB and FerretDB, but $pullAll is more explicit for exact matching (no condition expressions). Fix critical type mismatch bugs where ObjectId values were used against String[] memberIds arrays in Group queries: - config/delete-user.js: use string uid instead of ObjectId user._id - e2e/setup/cleanupUser.ts: convert userId.toString() before query Harden PermissionService.bulkUpdateResourcePermissions abort handling to prevent crash when abortTransaction is called after commitTransaction. All changes verified against FerretDB v2.7.0 and MongoDB Memory Server. * fix: harden transaction support probe for FerretDB compatibility Commit the transaction before aborting in supportsTransactions probe, and wrap abortTransaction in try-catch to prevent crashes when abort is called after a successful commit (observed behavior on FerretDB). * feat: add FerretDB compatibility test suite, retry utilities, and CI config Add comprehensive FerretDB integration test suite covering: - $pullAll scalar array operations - $pull with subdocument conditions - $lookup replacement (find + manual join) - $sample replacement (distinct + Fisher-Yates) - $bit and $bitsAllSet operations - Migration anti-join pattern - Multi-tenancy (useDb, scaling, write amplification) - Sharding proof-of-concept - Production operations (backup/restore, schema migration, deadlock retry) Add production retryWithBackoff utility for deadlock recovery during concurrent index creation on FerretDB/DocumentDB backends. Add UserController.spec.js tests for deleteUserController (runs in CI). Configure jest and eslint to isolate FerretDB tests from CI pipelines: - packages/data-schemas/jest.config.mjs: ignore misc/ directory - eslint.config.mjs: ignore packages/data-schemas/misc/ Include Docker Compose config for local FerretDB v2.7 + postgres-documentdb, dedicated jest/tsconfig for the test files, and multi-tenancy findings doc. * style: brace formatting in aclEntry.ts modifyPermissionBits * refactor: reorganize retry utilities and update imports - Moved retryWithBackoff utility to a new file `retry.ts` for better structure. - Updated imports in `orgOperations.ferretdb.spec.ts` to reflect the new location of retry utilities. - Removed old import statement for retryWithBackoff from index.ts to streamline exports. * test: add $pullAll coverage for ConversationTag and PermissionService Add integration tests for deleteConversationTag verifying $pullAll removes tags from conversations correctly, and for syncUserEntraGroupMemberships verifying $pullAll removes user from non-matching Entra groups while preserving local group membership. ---------
63 lines
1.9 KiB
TypeScript
63 lines
1.9 KiB
TypeScript
import logger from '~/config/winston';
|
|
|
|
export const CANCEL_RATE = 1.15;
|
|
|
|
/**
|
|
* Checks if the connected MongoDB deployment supports transactions
|
|
* This requires a MongoDB replica set configuration
|
|
*
|
|
* @returns True if transactions are supported, false otherwise
|
|
*/
|
|
export const supportsTransactions = async (
|
|
mongoose: typeof import('mongoose'),
|
|
): Promise<boolean> => {
|
|
try {
|
|
const session = await mongoose.startSession();
|
|
try {
|
|
session.startTransaction();
|
|
|
|
await mongoose.connection.db?.collection('__transaction_test__').findOne({}, { session });
|
|
|
|
await session.commitTransaction();
|
|
logger.debug('MongoDB transactions are supported');
|
|
return true;
|
|
} catch (transactionError: unknown) {
|
|
try {
|
|
await session.abortTransaction();
|
|
} catch (transactionError) {
|
|
/** best-effort abort */
|
|
logger.error(`[supportsTransactions] Error aborting transaction:`, transactionError);
|
|
}
|
|
logger.debug(
|
|
'MongoDB transactions not supported (transaction error):',
|
|
(transactionError as Error)?.message || 'Unknown error',
|
|
);
|
|
return false;
|
|
} finally {
|
|
await session.endSession();
|
|
}
|
|
} catch (error) {
|
|
logger.debug(
|
|
'MongoDB transactions not supported (session error):',
|
|
(error as Error)?.message || 'Unknown error',
|
|
);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Gets whether the current MongoDB deployment supports transactions
|
|
* Caches the result for performance
|
|
*
|
|
* @returns True if transactions are supported, false otherwise
|
|
*/
|
|
export const getTransactionSupport = async (
|
|
mongoose: typeof import('mongoose'),
|
|
transactionSupportCache: boolean | null,
|
|
): Promise<boolean> => {
|
|
let transactionsSupported = false;
|
|
if (transactionSupportCache === null) {
|
|
transactionsSupported = await supportsTransactions(mongoose);
|
|
}
|
|
return transactionsSupported;
|
|
};
|