Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ jobs:
- name: Install client dependencies
run: |
cd client
npm ci
npm i
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Install dependencies
run: npm ci
run: npm i
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Run build
run: npm run build
run: npm run build
12 changes: 4 additions & 8 deletions .github/workflows/deploy-staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,10 @@ jobs:
cd /home/modl/modl-admin
git stash
git pull origin dev
if git diff --name-only HEAD@{1} HEAD | grep -q "^package.*\.json$"; then
npm ci
fi
if git diff --name-only HEAD@{1} HEAD | grep -q "^client/package.*\.json$"; then
cd client
npm ci
cd ..
fi
npm i
cd client
npm i
cd ..
npm run build
pm2 reload modl-admin --wait-ready
if pm2 describe modl-admin | grep -q "online"; then
Expand Down
12 changes: 4 additions & 8 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,10 @@ jobs:
cd /home/modl/modl-admin
git stash
git pull origin main
if git diff --name-only HEAD@{1} HEAD | grep -q "^package.*\.json$"; then
npm ci
fi
if git diff --name-only HEAD@{1} HEAD | grep -q "^client/package.*\.json$"; then
cd client
npm ci
cd ..
fi
npm i
cd client
npm i
cd ..
npm run build
pm2 reload modl-admin --wait-ready
if pm2 describe modl-admin | grep -q "online"; then
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"author": "modl-gg",
"license": "AGPL-3.0-only",
"dependencies": {
"@modl-gg/shared-web": "^1.0.0",
"@modl-gg/shared-web": "1.0.1",
"@tanstack/react-query-devtools": "^5.81.2",
"@vitejs/plugin-react": "^4.6.0",
"compression": "^1.7.4",
Expand Down
60 changes: 60 additions & 0 deletions server/db/connectionManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import mongoose, { Connection } from 'mongoose';

let globalConnection: Connection | null = null;

/**
* Get or create a connection to the global MongoDB database
* This function returns the existing mongoose connection or creates a new one
*/
export async function connectToGlobalModlDb(): Promise<Connection> {
try {
// If we already have a connection and it's ready, return it
if (globalConnection && globalConnection.readyState === 1) {
return globalConnection;
}

// If mongoose is already connected, use the existing connection
if (mongoose.connection.readyState === 1) {
globalConnection = mongoose.connection;
return globalConnection;
}

// If not connected, establish a new connection
const mongoUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/modl-global';

// Set connection options for better timeout handling
const connectionOptions = {
serverSelectionTimeoutMS: 30000, // 30 seconds
socketTimeoutMS: 30000, // 30 seconds
bufferMaxEntries: 0,
bufferCommands: false,
};

await mongoose.connect(mongoUri, connectionOptions);
globalConnection = mongoose.connection;

console.log('✅ Global MongoDB connection established via connectionManager');
return globalConnection;
} catch (error) {
console.error('❌ Failed to connect to global MongoDB:', error);
throw error;
}
}

/**
* Close the global connection
*/
export async function closeGlobalConnection(): Promise<void> {
if (globalConnection) {
await globalConnection.close();
globalConnection = null;
console.log('🔒 Global MongoDB connection closed');
}
}

/**
* Get the current connection status
*/
export function getConnectionStatus(): number {
return globalConnection?.readyState ?? mongoose.connection.readyState;
}
27 changes: 16 additions & 11 deletions server/routes/servers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import mongoose, { Schema, model, Document, Model } from 'mongoose';
import { IModlServer as IModlServerShared, ApiResponse, ModlServerSchema } from '@modl-gg/shared-web';
import { requireAuth } from '../middleware/authMiddleware';
import { discordWebhookService } from '../services/DiscordWebhookService';
import { connectToGlobalModlDb } from '../db/connectionManager';

type IModlServer = IModlServerShared & Document;

Expand Down Expand Up @@ -165,8 +166,9 @@ router.get('/:id/stats', async (req: Request, res: Response) => {
});
}

// Connect to the specific server's database
const serverDb = mongoose.connection.useDb(server.databaseName, { useCache: true });
// Connect to the specific server's database using connection manager for proper timeout settings
const globalConnection = await connectToGlobalModlDb();
const serverDb = globalConnection.useDb(server.databaseName, { useCache: true });

// Fetch stats from the server's database
const [
Expand Down Expand Up @@ -460,18 +462,21 @@ router.post('/:id/reset-database', async (req: Request, res: Response) => {
// Only drop the database if it exists and is configured
if (server.databaseName) {
try {
// Check if main connection is ready before attempting database operations
if (mongoose.connection.readyState !== 1) {
console.warn(`MongoDB connection not ready (state: ${mongoose.connection.readyState}). Skipping database drop for ${server.databaseName}`);
// Use connection manager to get a connection with proper timeout settings
const globalConnection = await connectToGlobalModlDb();

if (globalConnection.readyState !== 1) {
console.warn(`Global MongoDB connection not ready (state: ${globalConnection.readyState}). Skipping database drop for ${server.databaseName}`);
} else {
const serverDb = mongoose.connection.useDb(server.databaseName, { useCache: true });

// Add timeout to prevent hanging
// Use the global connection to access the specific server database
const serverDb = globalConnection.useDb(server.databaseName, { useCache: false });

// Add timeout to prevent hanging - increased to 30 seconds to match connection timeout settings
const dropPromise = serverDb.dropDatabase();
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Database drop operation timed out after 5 seconds')), 5000)
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Database drop operation timed out after 30 seconds')), 30000)
);

await Promise.race([dropPromise, timeoutPromise]);
console.log(`Database ${server.databaseName} dropped for server ${server.serverName}`);
}
Expand Down