fix: implement persistent MongoDB connections and resolve race conditions
- Replace connect/disconnect pattern with persistent connection pool - Add explicit database initialization on server startup - Remove all dbDisconnect() calls from API endpoints to prevent race conditions - Fix MongoNotConnectedError when scheduler runs concurrently with API requests - Add connection pooling with proper MongoDB driver options - Add safety check for recipes array in favorites utility 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { Recipe } from '../../../../models/Recipe';
|
||||
import { dbConnect, dbDisconnect } from '../../../../utils/db';
|
||||
import { dbConnect } from '../../../../utils/db';
|
||||
import { error } from '@sveltejs/kit';
|
||||
// header: use for bearer token for now
|
||||
// recipe json in body
|
||||
@@ -22,7 +22,6 @@ export const POST: RequestHandler = async ({request, cookies, locals}) => {
|
||||
} catch(e){
|
||||
throw error(400, e)
|
||||
}
|
||||
await dbDisconnect();
|
||||
return new Response(JSON.stringify({msg: "Added recipe successfully"}),{
|
||||
status: 200,
|
||||
});
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { Recipe } from '../../../../models/Recipe';
|
||||
import { dbConnect, dbDisconnect } from '../../../../utils/db';
|
||||
import { dbConnect } from '../../../../utils/db';
|
||||
import type {RecipeModelType} from '../../../../types/types';
|
||||
import { error } from '@sveltejs/kit';
|
||||
// header: use for bearer token for now
|
||||
@@ -14,7 +14,6 @@ export const POST: RequestHandler = async ({request, locals}) => {
|
||||
const short_name = message.old_short_name
|
||||
await dbConnect();
|
||||
await Recipe.findOneAndDelete({short_name: short_name});
|
||||
await dbDisconnect();
|
||||
return new Response(JSON.stringify({msg: "Deleted recipe successfully"}),{
|
||||
status: 200,
|
||||
});
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { Recipe } from '../../../../models/Recipe';
|
||||
import { dbConnect, dbDisconnect } from '../../../../utils/db';
|
||||
import { dbConnect } from '../../../../utils/db';
|
||||
import type {RecipeModelType} from '../../../../types/types';
|
||||
import { error } from '@sveltejs/kit';
|
||||
// header: use for bearer token for now
|
||||
@@ -15,7 +15,6 @@ export const POST: RequestHandler = async ({request, locals}) => {
|
||||
else{
|
||||
await dbConnect();
|
||||
await Recipe.findOneAndUpdate({short_name: message.old_short_name }, recipe_json);
|
||||
await dbDisconnect();
|
||||
return new Response(JSON.stringify({msg: "Edited recipe successfully"}),{
|
||||
status: 200,
|
||||
});
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
import { UserFavorites } from '../../../../models/UserFavorites';
|
||||
import { Recipe } from '../../../../models/Recipe';
|
||||
import { dbConnect, dbDisconnect } from '../../../../utils/db';
|
||||
import { dbConnect } from '../../../../utils/db';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
@@ -19,13 +19,11 @@ export const GET: RequestHandler = async ({ locals }) => {
|
||||
username: session.user.nickname
|
||||
}).lean();
|
||||
|
||||
await dbDisconnect();
|
||||
|
||||
return json({
|
||||
favorites: userFavorites?.favorites || []
|
||||
});
|
||||
} catch (e) {
|
||||
await dbDisconnect();
|
||||
throw error(500, 'Failed to fetch favorites');
|
||||
}
|
||||
};
|
||||
@@ -49,8 +47,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
// Validate that the recipe exists and get its ObjectId
|
||||
const recipe = await Recipe.findOne({ short_name: recipeId });
|
||||
if (!recipe) {
|
||||
await dbDisconnect();
|
||||
throw error(404, 'Recipe not found');
|
||||
throw error(404, 'Recipe not found');
|
||||
}
|
||||
|
||||
await UserFavorites.findOneAndUpdate(
|
||||
@@ -59,11 +56,9 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
{ upsert: true, new: true }
|
||||
);
|
||||
|
||||
await dbDisconnect();
|
||||
|
||||
return json({ success: true });
|
||||
} catch (e) {
|
||||
await dbDisconnect();
|
||||
if (e instanceof Error && e.message.includes('404')) {
|
||||
throw e;
|
||||
}
|
||||
@@ -90,8 +85,7 @@ export const DELETE: RequestHandler = async ({ request, locals }) => {
|
||||
// Find the recipe's ObjectId
|
||||
const recipe = await Recipe.findOne({ short_name: recipeId });
|
||||
if (!recipe) {
|
||||
await dbDisconnect();
|
||||
throw error(404, 'Recipe not found');
|
||||
throw error(404, 'Recipe not found');
|
||||
}
|
||||
|
||||
await UserFavorites.findOneAndUpdate(
|
||||
@@ -99,11 +93,9 @@ export const DELETE: RequestHandler = async ({ request, locals }) => {
|
||||
{ $pull: { favorites: recipe._id } }
|
||||
);
|
||||
|
||||
await dbDisconnect();
|
||||
|
||||
return json({ success: true });
|
||||
} catch (e) {
|
||||
await dbDisconnect();
|
||||
if (e instanceof Error && e.message.includes('404')) {
|
||||
throw e;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
import { UserFavorites } from '../../../../../../models/UserFavorites';
|
||||
import { Recipe } from '../../../../../../models/Recipe';
|
||||
import { dbConnect, dbDisconnect } from '../../../../../../utils/db';
|
||||
import { dbConnect } from '../../../../../../utils/db';
|
||||
import { error } from '@sveltejs/kit';
|
||||
|
||||
export const GET: RequestHandler = async ({ locals, params }) => {
|
||||
@@ -17,7 +17,6 @@ export const GET: RequestHandler = async ({ locals, params }) => {
|
||||
// Find the recipe by short_name to get its ObjectId
|
||||
const recipe = await Recipe.findOne({ short_name: params.shortName });
|
||||
if (!recipe) {
|
||||
await dbDisconnect();
|
||||
throw error(404, 'Recipe not found');
|
||||
}
|
||||
|
||||
@@ -27,13 +26,11 @@ export const GET: RequestHandler = async ({ locals, params }) => {
|
||||
favorites: recipe._id
|
||||
}).lean();
|
||||
|
||||
await dbDisconnect();
|
||||
|
||||
return json({
|
||||
isFavorite: !!userFavorites
|
||||
});
|
||||
} catch (e) {
|
||||
await dbDisconnect();
|
||||
if (e instanceof Error && e.message.includes('404')) {
|
||||
throw e;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
import { UserFavorites } from '../../../../../models/UserFavorites';
|
||||
import { Recipe } from '../../../../../models/Recipe';
|
||||
import { dbConnect, dbDisconnect } from '../../../../../utils/db';
|
||||
import { dbConnect } from '../../../../../utils/db';
|
||||
import type { RecipeModelType } from '../../../../../types/types';
|
||||
import { error } from '@sveltejs/kit';
|
||||
|
||||
@@ -20,7 +20,6 @@ export const GET: RequestHandler = async ({ locals }) => {
|
||||
}).lean();
|
||||
|
||||
if (!userFavorites?.favorites?.length) {
|
||||
await dbDisconnect();
|
||||
return json([]);
|
||||
}
|
||||
|
||||
@@ -28,13 +27,11 @@ export const GET: RequestHandler = async ({ locals }) => {
|
||||
_id: { $in: userFavorites.favorites }
|
||||
}).lean() as RecipeModelType[];
|
||||
|
||||
await dbDisconnect();
|
||||
|
||||
recipes = JSON.parse(JSON.stringify(recipes));
|
||||
|
||||
return json(recipes);
|
||||
} catch (e) {
|
||||
await dbDisconnect();
|
||||
throw error(500, 'Failed to fetch favorite recipes');
|
||||
}
|
||||
};
|
@@ -1,13 +1,12 @@
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
import { Recipe } from '../../../../../models/Recipe';
|
||||
import { dbConnect, dbDisconnect } from '../../../../../utils/db';
|
||||
import { dbConnect } from '../../../../../utils/db';
|
||||
import type {RecipeModelType} from '../../../../../types/types';
|
||||
import { error } from '@sveltejs/kit';
|
||||
|
||||
export const GET: RequestHandler = async ({params}) => {
|
||||
await dbConnect();
|
||||
let recipe = (await Recipe.findOne({ short_name: params.name}).lean()) as RecipeModelType[];
|
||||
await dbDisconnect();
|
||||
|
||||
recipe = JSON.parse(JSON.stringify(recipe));
|
||||
if(recipe == null){
|
||||
|
@@ -1,12 +1,11 @@
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
import type { BriefRecipeType } from '../../../../../types/types';
|
||||
import { Recipe } from '../../../../../models/Recipe'
|
||||
import { dbConnect, dbDisconnect } from '../../../../../utils/db';
|
||||
import { dbConnect } from '../../../../../utils/db';
|
||||
import { rand_array } from '$lib/js/randomize';
|
||||
|
||||
export const GET: RequestHandler = async ({params}) => {
|
||||
await dbConnect();
|
||||
let found_brief = rand_array(await Recipe.find({}, 'name short_name tags category icon description season dateModified').lean()) as BriefRecipeType[];
|
||||
await dbDisconnect();
|
||||
return json(JSON.parse(JSON.stringify(found_brief)));
|
||||
};
|
||||
|
@@ -1,12 +1,11 @@
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
import { Recipe } from '../../../../../models/Recipe';
|
||||
import { dbConnect, dbDisconnect } from '../../../../../utils/db';
|
||||
import { dbConnect } from '../../../../../utils/db';
|
||||
import type {BriefRecipeType} from '../../../../../types/types';
|
||||
|
||||
export const GET: RequestHandler = async ({params}) => {
|
||||
await dbConnect();
|
||||
let categories = (await Recipe.distinct('category').lean());
|
||||
await dbDisconnect();
|
||||
|
||||
categories= JSON.parse(JSON.stringify(categories));
|
||||
return json(categories);
|
||||
|
@@ -1,13 +1,12 @@
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
import { Recipe } from '../../../../../../models/Recipe';
|
||||
import { dbConnect, dbDisconnect } from '../../../../../../utils/db';
|
||||
import { dbConnect } from '../../../../../../utils/db';
|
||||
import type {BriefRecipeType} from '../../../../../../types/types';
|
||||
import { rand_array } from '$lib/js/randomize';
|
||||
|
||||
export const GET: RequestHandler = async ({params}) => {
|
||||
await dbConnect();
|
||||
let recipes = rand_array(await Recipe.find({category: params.category}, 'name short_name images tags category icon description season dateModified').lean()) as BriefRecipeType[];
|
||||
await dbDisconnect();
|
||||
|
||||
recipes = JSON.parse(JSON.stringify(recipes));
|
||||
return json(recipes);
|
||||
|
@@ -1,12 +1,11 @@
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
import { Recipe } from '../../../../../models/Recipe';
|
||||
import { dbConnect, dbDisconnect } from '../../../../../utils/db';
|
||||
import { dbConnect } from '../../../../../utils/db';
|
||||
import type {BriefRecipeType} from '../../../../../types/types';
|
||||
|
||||
export const GET: RequestHandler = async ({params}) => {
|
||||
await dbConnect();
|
||||
let icons = (await Recipe.distinct('icon').lean());
|
||||
await dbDisconnect();
|
||||
|
||||
icons = JSON.parse(JSON.stringify(icons));
|
||||
return json(icons);
|
||||
|
@@ -1,13 +1,12 @@
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
import { Recipe } from '../../../../../../models/Recipe';
|
||||
import { dbConnect, dbDisconnect } from '../../../../../../utils/db';
|
||||
import { dbConnect } from '../../../../../../utils/db';
|
||||
import type {BriefRecipeType} from '../../../../../../types/types';
|
||||
import { rand_array } from '$lib/js/randomize';
|
||||
|
||||
export const GET: RequestHandler = async ({params}) => {
|
||||
await dbConnect();
|
||||
let recipes = rand_array(await Recipe.find({icon: params.icon}, 'name short_name images tags category icon description season dateModified').lean()) as BriefRecipeType[];
|
||||
await dbDisconnect();
|
||||
|
||||
recipes = JSON.parse(JSON.stringify(recipes));
|
||||
return json(recipes);
|
||||
|
@@ -1,13 +1,12 @@
|
||||
import type {rand_array} from '$lib/js/randomize';
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
import { Recipe } from '../../../../../../models/Recipe'
|
||||
import { dbConnect, dbDisconnect } from '../../../../../../utils/db';
|
||||
import { dbConnect } from '../../../../../../utils/db';
|
||||
import { rand_array } from '$lib/js/randomize';
|
||||
|
||||
export const GET: RequestHandler = async ({params}) => {
|
||||
await dbConnect();
|
||||
let found_in_season = rand_array(await Recipe.find({season: params.month, icon: {$ne: "🍽️"}}, 'name short_name images tags category icon description season dateModified').lean());
|
||||
await dbDisconnect();
|
||||
found_in_season = JSON.parse(JSON.stringify(found_in_season));
|
||||
return json(found_in_season);
|
||||
};
|
||||
|
@@ -1,12 +1,11 @@
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
import { Recipe } from '../../../../../models/Recipe';
|
||||
import { dbConnect, dbDisconnect } from '../../../../../utils/db';
|
||||
import { dbConnect } from '../../../../../utils/db';
|
||||
import type {BriefRecipeType} from '../../../../../types/types';
|
||||
|
||||
export const GET: RequestHandler = async ({params}) => {
|
||||
await dbConnect();
|
||||
let categories = (await Recipe.distinct('tags').lean());
|
||||
await dbDisconnect();
|
||||
|
||||
categories= JSON.parse(JSON.stringify(categories));
|
||||
return json(categories);
|
||||
|
@@ -1,13 +1,12 @@
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
import { Recipe } from '../../../../../../models/Recipe';
|
||||
import { dbConnect, dbDisconnect } from '../../../../../../utils/db';
|
||||
import { dbConnect } from '../../../../../../utils/db';
|
||||
import type {BriefRecipeType} from '../../../../../../types/types';
|
||||
import { rand_array } from '$lib/js/randomize';
|
||||
|
||||
export const GET: RequestHandler = async ({params}) => {
|
||||
await dbConnect();
|
||||
let recipes = rand_array(await Recipe.find({tags: params.tag}, 'name short_name images tags category icon description season dateModified').lean()) as BriefRecipeType[];
|
||||
await dbDisconnect();
|
||||
|
||||
recipes = JSON.parse(JSON.stringify(recipes));
|
||||
return json(recipes);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
import { Recipe } from '../../../../../models/Recipe';
|
||||
import { dbConnect, dbDisconnect } from '../../../../../utils/db';
|
||||
import { dbConnect } from '../../../../../utils/db';
|
||||
import { generateRecipeJsonLd } from '$lib/js/recipeJsonLd';
|
||||
import type { RecipeModelType } from '../../../../../types/types';
|
||||
import { error } from '@sveltejs/kit';
|
||||
@@ -8,7 +8,6 @@ import { error } from '@sveltejs/kit';
|
||||
export const GET: RequestHandler = async ({ params, setHeaders }) => {
|
||||
await dbConnect();
|
||||
let recipe = (await Recipe.findOne({ short_name: params.name }).lean()) as RecipeModelType;
|
||||
await dbDisconnect();
|
||||
|
||||
recipe = JSON.parse(JSON.stringify(recipe));
|
||||
if (recipe == null) {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
import type { BriefRecipeType } from '../../../../types/types';
|
||||
import { Recipe } from '../../../../models/Recipe';
|
||||
import { dbConnect, dbDisconnect } from '../../../../utils/db';
|
||||
import { dbConnect } from '../../../../utils/db';
|
||||
|
||||
export const GET: RequestHandler = async ({ url, locals }) => {
|
||||
await dbConnect();
|
||||
@@ -64,11 +64,9 @@ export const GET: RequestHandler = async ({ url, locals }) => {
|
||||
});
|
||||
}
|
||||
|
||||
await dbDisconnect();
|
||||
return json(JSON.parse(JSON.stringify(recipes)));
|
||||
|
||||
} catch (error) {
|
||||
await dbDisconnect();
|
||||
return json({ error: 'Search failed' }, { status: 500 });
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user