Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a5e55ca96 | |||
| a72741c0d9 | |||
| e7ed7006fd |
+4
-4
@@ -40,10 +40,10 @@ const config = {
|
|||||||
keepAliveInitialDelayMillis: 0
|
keepAliveInitialDelayMillis: 0
|
||||||
},
|
},
|
||||||
pool: {
|
pool: {
|
||||||
min: 2,
|
min: 5,
|
||||||
max: 10,
|
max: 25,
|
||||||
acquireTimeoutMillis: 30000,
|
acquireTimeoutMillis: 60000,
|
||||||
createTimeoutMillis: 30000,
|
createTimeoutMillis: 60000,
|
||||||
idleTimeoutMillis: 30000,
|
idleTimeoutMillis: 30000,
|
||||||
reapIntervalMillis: 1000,
|
reapIntervalMillis: 1000,
|
||||||
createRetryIntervalMillis: 200,
|
createRetryIntervalMillis: 200,
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "picpeak-backend",
|
"name": "picpeak-backend",
|
||||||
"version": "1.0.69",
|
"version": "1.0.70",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "picpeak-backend",
|
"name": "picpeak-backend",
|
||||||
"version": "1.0.69",
|
"version": "1.0.70",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"adm-zip": "^0.5.16",
|
"adm-zip": "^0.5.16",
|
||||||
"archiver": "^5.3.1",
|
"archiver": "^5.3.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "picpeak-backend",
|
"name": "picpeak-backend",
|
||||||
"version": "1.0.69",
|
"version": "1.0.70",
|
||||||
"description": "Backend for PicPeak event photo sharing platform",
|
"description": "Backend for PicPeak event photo sharing platform",
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -4,6 +4,33 @@ const knexConfig = require('../../knexfile');
|
|||||||
// Create database connection with built-in retry logic
|
// Create database connection with built-in retry logic
|
||||||
const db = knex(knexConfig);
|
const db = knex(knexConfig);
|
||||||
|
|
||||||
|
// Connection retry configuration
|
||||||
|
const MAX_RETRIES = 3;
|
||||||
|
const RETRY_DELAY = 1000;
|
||||||
|
|
||||||
|
// Wrapper function to handle connection retries
|
||||||
|
async function withRetry(queryFn, retries = MAX_RETRIES) {
|
||||||
|
for (let i = 0; i < retries; i++) {
|
||||||
|
try {
|
||||||
|
return await queryFn();
|
||||||
|
} catch (error) {
|
||||||
|
const isConnectionError = error.message && (
|
||||||
|
error.message.includes('Connection terminated unexpectedly') ||
|
||||||
|
error.message.includes('Connection ended unexpectedly') ||
|
||||||
|
error.message.includes('ECONNREFUSED') ||
|
||||||
|
error.message.includes('ETIMEDOUT')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isConnectionError && i < retries - 1) {
|
||||||
|
console.log(`Database connection error, retrying in ${RETRY_DELAY}ms... (attempt ${i + 1}/${retries})`);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, RETRY_DELAY * (i + 1)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function initializeDatabase() {
|
async function initializeDatabase() {
|
||||||
// Events table
|
// Events table
|
||||||
const hasEventsTable = await db.schema.hasTable('events');
|
const hasEventsTable = await db.schema.hasTable('events');
|
||||||
@@ -225,4 +252,4 @@ async function logActivity(activityType, metadata = {}, eventId = null, actor =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { db, initializeDatabase, logActivity };
|
module.exports = { db, initializeDatabase, logActivity, withRetry };
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const { db } = require('../database/db');
|
const { db, withRetry } = require('../database/db');
|
||||||
const { formatBoolean } = require('../utils/dbCompat');
|
const { formatBoolean } = require('../utils/dbCompat');
|
||||||
|
|
||||||
// Middleware to verify gallery access
|
// Middleware to verify gallery access
|
||||||
@@ -11,13 +11,15 @@ async function verifyGalleryAccess(req, res, next) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
||||||
const event = await db('events')
|
const event = await withRetry(async () => {
|
||||||
.where({
|
return await db('events')
|
||||||
id: decoded.eventId,
|
.where({
|
||||||
is_active: formatBoolean(true),
|
id: decoded.eventId,
|
||||||
is_archived: formatBoolean(false)
|
is_active: formatBoolean(true),
|
||||||
})
|
is_archived: formatBoolean(false)
|
||||||
.first();
|
})
|
||||||
|
.first();
|
||||||
|
});
|
||||||
|
|
||||||
if (!event) {
|
if (!event) {
|
||||||
return res.status(404).json({ error: 'Gallery not found or expired' });
|
return res.status(404).json({ error: 'Gallery not found or expired' });
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const DEFAULT_SESSION_TIMEOUT = 60 * 60 * 1000;
|
|||||||
// Cache for session timeout setting
|
// Cache for session timeout setting
|
||||||
let cachedTimeout = null;
|
let cachedTimeout = null;
|
||||||
let cacheExpiry = 0;
|
let cacheExpiry = 0;
|
||||||
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
|
const CACHE_DURATION = 30 * 60 * 1000; // 30 minutes - reduced DB queries
|
||||||
|
|
||||||
// Clean up expired sessions every 5 minutes
|
// Clean up expired sessions every 5 minutes
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const { db } = require('../database/db');
|
const { db, withRetry } = require('../database/db');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
// Get public settings (branding and theme)
|
// Get public settings (branding and theme)
|
||||||
@@ -7,12 +7,14 @@ router.get('/', async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
// Fetch branding, theme, general, and security settings
|
// Fetch branding, theme, general, and security settings
|
||||||
// Note: We include analytics in the query but it might not exist yet
|
// Note: We include analytics in the query but it might not exist yet
|
||||||
const settings = await db('app_settings')
|
const settings = await withRetry(async () => {
|
||||||
.where(function() {
|
return await db('app_settings')
|
||||||
this.whereIn('setting_type', ['branding', 'theme', 'general', 'security', 'analytics'])
|
.where(function() {
|
||||||
.orWhere('setting_key', 'like', 'analytics_%');
|
this.whereIn('setting_type', ['branding', 'theme', 'general', 'security', 'analytics'])
|
||||||
})
|
.orWhere('setting_key', 'like', 'analytics_%');
|
||||||
.select('setting_key', 'setting_value');
|
})
|
||||||
|
.select('setting_key', 'setting_value');
|
||||||
|
});
|
||||||
|
|
||||||
// Convert to object format
|
// Convert to object format
|
||||||
const settingsObject = {};
|
const settingsObject = {};
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ async function processEmailQueue() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start email queue processor
|
// Start email queue processor
|
||||||
setInterval(processEmailQueue, 60000); // Process every minute
|
// DISABLED: Using emailProcessor.js instead to prevent duplicate connections
|
||||||
|
// setInterval(processEmailQueue, 60000); // Process every minute
|
||||||
|
|
||||||
module.exports = { sendEmail, processEmailQueue };
|
module.exports = { sendEmail, processEmailQueue };
|
||||||
|
|||||||
@@ -119,11 +119,14 @@ function validatePassword(password, options = {}) {
|
|||||||
*/
|
*/
|
||||||
async function getPasswordComplexitySettings() {
|
async function getPasswordComplexitySettings() {
|
||||||
try {
|
try {
|
||||||
const db = require('../db');
|
const { db, withRetry } = require('../database/db');
|
||||||
const settings = await db('app_settings')
|
|
||||||
.where('setting_key', 'password_complexity')
|
// Use retry wrapper to handle connection failures
|
||||||
.where('setting_type', 'security')
|
const settings = await withRetry(async () => {
|
||||||
.first();
|
return await db('app_settings')
|
||||||
|
.where('setting_key', 'security_password_complexity_level')
|
||||||
|
.first();
|
||||||
|
});
|
||||||
|
|
||||||
if (!settings || !settings.setting_value) {
|
if (!settings || !settings.setting_value) {
|
||||||
return 'moderate'; // Default
|
return 'moderate'; // Default
|
||||||
@@ -136,7 +139,7 @@ async function getPasswordComplexitySettings() {
|
|||||||
return value;
|
return value;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to get password complexity settings:', error);
|
logger.error('Failed to get password complexity settings:', error);
|
||||||
return 'moderate'; // Default on error
|
return 'moderate'; // Default on error - ensures app continues working
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user