From 88967ba9d3b831b76016f128f3064455863615e9 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Fri, 23 Jan 2026 10:37:47 +0100 Subject: [PATCH] Implement model synchronization with timeout handling in sequelize.js - Added a helper function to synchronize models with a timeout, improving error handling for long-running sync operations. - Updated the syncModelsAlways function to utilize the new timeout feature, providing better control over model synchronization and preventing indefinite hangs. - Enhanced logging to indicate model sync progress and timeout occurrences, improving visibility during deployment. --- backend/utils/sequelize.js | 44 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/backend/utils/sequelize.js b/backend/utils/sequelize.js index 69c47c4..3ab1747 100644 --- a/backend/utils/sequelize.js +++ b/backend/utils/sequelize.js @@ -435,12 +435,39 @@ async function updateFalukantUserMoney(falukantUserId, moneyChange, activity, ch } } +// Helper: Sync mit Timeout +const syncModelWithTimeout = async (model, timeoutMs = 60000) => { + const timeoutPromise = new Promise((_, reject) => { + setTimeout(() => reject(new Error(`Model sync timeout after ${timeoutMs}ms`)), timeoutMs); + }); + + try { + await Promise.race([ + model.sync({ alter: true, force: false, constraints: false }), + timeoutPromise + ]); + } catch (error) { + if (error.message.includes('timeout')) { + console.warn(` ⚠️ ${model.name} sync timeout nach ${timeoutMs}ms - überspringe...`); + return false; + } + throw error; + } + return true; +}; + // Immer Schema-Updates (für Deployment) const syncModelsAlways = async (models) => { console.log('🔍 Deployment-Modus: Führe immer Schema-Updates durch...'); + const modelArray = Object.values(models); + const totalModels = modelArray.length; + let currentModel = 0; + try { - for (const model of Object.values(models)) { + for (const model of modelArray) { + currentModel++; + console.log(` 🔄 Syncing model ${model.name} (${currentModel}/${totalModels})...`); // Temporarily remove VIRTUAL fields before sync to prevent sync errors const originalAttributes = model.rawAttributes; const virtualFields = {}; @@ -585,7 +612,20 @@ const syncModelsAlways = async (models) => { } } - await model.sync({ alter: true, force: false, constraints: false }); + // Verwende syncModelWithTimeout für große Tabellen + const syncSuccess = await syncModelWithTimeout(model, 60000); + if (!syncSuccess) { + console.warn(` ⚠️ ${model.name} wurde übersprungen aufgrund von Timeout`); + // Restore associations before continuing + if (associationKeys.length > 0) { + model.associations = originalAssociations; + } + // Restore virtual fields + for (const [key, attr] of Object.entries(virtualFields)) { + model.rawAttributes[key] = attr; + } + continue; + } } catch (syncError) { // Wenn Sequelize einen "mehr als eine Zeile" Fehler hat, überspringe das Model // Dies kann durch doppelte pg_description Einträge oder mehrere Tabellen mit demselben Namen verursacht werden