mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-21 14:08:15 +02:00
Update backup service to use native scheduling and fix production errors
Replaced node-cron with native setInterval for backup scheduling to resolve production issues related to dynamic requires. Replit-Commit-Author: Agent Replit-Commit-Session-Id: db1bcb73-80c1-4bff-8236-4ced2c07f75f Replit-Commit-Checkpoint-Type: full_checkpoint
This commit is contained in:
1 parent
68da9f1926
commit
f3785fb428
2 files changed
+233
-14
No files matched your search
+194
@@ -0,0 +1,194 @@
|
|||||||
|
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
|
||||||
|
isProduction: true,
|
||||||
|
|
||||||
|
hasDbUrl: true,
|
||||||
|
|
||||||
|
dbHost: 'logiflow-db'
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
🐳 PRODUCTION: Using standard PostgreSQL
|
||||||
|
|
||||||
|
✅ PostgreSQL connection test successful
|
||||||
|
|
||||||
|
🔗 Database initialization: {
|
||||||
|
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
|
||||||
|
isProduction: true,
|
||||||
|
|
||||||
|
hasDbUrl: true,
|
||||||
|
|
||||||
|
dbHost: 'logiflow-db:5432'
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
✅ Using DatabaseStorage (production PostgreSQL)
|
||||||
|
|
||||||
|
file:///app/dist/index.js:11
|
||||||
|
|
||||||
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
^
|
||||||
|
|
||||||
|
Error: Dynamic require of "events" is not supported
|
||||||
|
|
||||||
|
at file:///app/dist/index.js:11:9
|
||||||
|
|
||||||
|
at node_modules/node-cron/dist/esm/tasks/inline-scheduled-task.js (file:///app/dist/index.js:5840:36)
|
||||||
|
|
||||||
|
at __require2 (file:///app/dist/index.js:17:50)
|
||||||
|
|
||||||
|
at node_modules/node-cron/dist/esm/node-cron.js (file:///app/dist/index.js:6321:35)
|
||||||
|
|
||||||
|
at __require2 (file:///app/dist/index.js:17:50)
|
||||||
|
|
||||||
|
at file:///app/dist/index.js:7062:32
|
||||||
|
|
||||||
|
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
|
||||||
|
|
||||||
|
Node.js v20.19.4
|
||||||
|
|
||||||
|
Applying DLC migration...
|
||||||
|
|
||||||
|
NOTICE: column "stock_epuise" of relation "dlc_products" already exists, skipping
|
||||||
|
|
||||||
|
NOTICE: column "stock_epuise_by" of relation "dlc_products" already exists, skipping
|
||||||
|
|
||||||
|
NOTICE: column "stock_epuise_at" of relation "dlc_products" already exists, skipping
|
||||||
|
|
||||||
|
NOTICE: relation "idx_dlc_products_stock_epuise" already exists, skipping
|
||||||
|
|
||||||
|
ALTER TABLE
|
||||||
|
|
||||||
|
␍CREATE INDEX
|
||||||
|
|
||||||
|
🔗 Database initialization: {
|
||||||
|
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
|
||||||
|
isProduction: true,
|
||||||
|
|
||||||
|
hasDbUrl: true,
|
||||||
|
|
||||||
|
dbHost: 'logiflow-db'
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
🐳 PRODUCTION: Using standard PostgreSQL
|
||||||
|
|
||||||
|
✅ PostgreSQL connection test successful
|
||||||
|
|
||||||
|
🔗 Database initialization: {
|
||||||
|
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
|
||||||
|
isProduction: true,
|
||||||
|
|
||||||
|
hasDbUrl: true,
|
||||||
|
|
||||||
|
dbHost: 'logiflow-db:5432'
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
✅ Using DatabaseStorage (production PostgreSQL)
|
||||||
|
|
||||||
|
file:///app/dist/index.js:11
|
||||||
|
|
||||||
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
^
|
||||||
|
|
||||||
|
Error: Dynamic require of "events" is not supported
|
||||||
|
|
||||||
|
at file:///app/dist/index.js:11:9
|
||||||
|
|
||||||
|
at node_modules/node-cron/dist/esm/tasks/inline-scheduled-task.js (file:///app/dist/index.js:5840:36)
|
||||||
|
|
||||||
|
at __require2 (file:///app/dist/index.js:17:50)
|
||||||
|
|
||||||
|
at node_modules/node-cron/dist/esm/node-cron.js (file:///app/dist/index.js:6321:35)
|
||||||
|
|
||||||
|
at __require2 (file:///app/dist/index.js:17:50)
|
||||||
|
|
||||||
|
at file:///app/dist/index.js:7062:32
|
||||||
|
|
||||||
|
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
|
||||||
|
|
||||||
|
Node.js v20.19.4
|
||||||
|
|
||||||
|
Applying DLC migration...
|
||||||
|
|
||||||
|
NOTICE: column "stock_epuise" of relation "dlc_products" already exists, skipping
|
||||||
|
|
||||||
|
NOTICE: column "stock_epuise_by" of relation "dlc_products" already exists, skipping
|
||||||
|
|
||||||
|
NOTICE: column "stock_epuise_at" of relation "dlc_products" already exists, skipping
|
||||||
|
|
||||||
|
NOTICE: relation "idx_dlc_products_stock_epuise" already exists, skipping
|
||||||
|
|
||||||
|
ALTER TABLE
|
||||||
|
|
||||||
|
␍CREATE INDEX
|
||||||
|
|
||||||
|
🔗 Database initialization: {
|
||||||
|
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
|
||||||
|
isProduction: true,
|
||||||
|
|
||||||
|
hasDbUrl: true,
|
||||||
|
|
||||||
|
dbHost: 'logiflow-db'
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
🐳 PRODUCTION: Using standard PostgreSQL
|
||||||
|
|
||||||
|
✅ PostgreSQL connection test successful
|
||||||
|
|
||||||
|
🔗 Database initialization: {
|
||||||
|
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
|
||||||
|
isProduction: true,
|
||||||
|
|
||||||
|
hasDbUrl: true,
|
||||||
|
|
||||||
|
dbHost: 'logiflow-db:5432'
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
✅ Using DatabaseStorage (production PostgreSQL)
|
||||||
|
|
||||||
|
file:///app/dist/index.js:11
|
||||||
|
|
||||||
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
^
|
||||||
|
|
||||||
|
Error: Dynamic require of "events" is not supported
|
||||||
|
|
||||||
|
at file:///app/dist/index.js:11:9
|
||||||
|
|
||||||
|
at node_modules/node-cron/dist/esm/tasks/inline-scheduled-task.js (file:///app/dist/index.js:5840:36)
|
||||||
|
|
||||||
|
at __require2 (file:///app/dist/index.js:17:50)
|
||||||
|
|
||||||
|
at node_modules/node-cron/dist/esm/node-cron.js (file:///app/dist/index.js:6321:35)
|
||||||
|
|
||||||
|
at __require2 (file:///app/dist/index.js:17:50)
|
||||||
|
|
||||||
|
at file:///app/dist/index.js:7062:32
|
||||||
|
|
||||||
|
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
|
||||||
|
|
||||||
|
Node.js v20.19.4
|
||||||
+39
-14
@@ -4,7 +4,6 @@ import fs from 'fs';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import { eq, desc } from "drizzle-orm";
|
import { eq, desc } from "drizzle-orm";
|
||||||
import cron from 'node-cron';
|
|
||||||
import { db } from "./db";
|
import { db } from "./db";
|
||||||
import { databaseBackups } from "@shared/schema";
|
import { databaseBackups } from "@shared/schema";
|
||||||
import type { DatabaseBackup, InsertDatabaseBackup } from "@shared/schema";
|
import type { DatabaseBackup, InsertDatabaseBackup } from "@shared/schema";
|
||||||
@@ -14,6 +13,7 @@ const execAsync = promisify(exec);
|
|||||||
export class BackupService {
|
export class BackupService {
|
||||||
private backupDir: string;
|
private backupDir: string;
|
||||||
private maxBackups = 10;
|
private maxBackups = 10;
|
||||||
|
private lastAutomaticBackupDate: string | null = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Use /app/backups in production (with proper permissions), or use env variable
|
// Use /app/backups in production (with proper permissions), or use env variable
|
||||||
@@ -212,21 +212,46 @@ export class BackupService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private scheduleAutomaticBackup(): void {
|
private scheduleAutomaticBackup(): void {
|
||||||
// Use node-cron for reliable scheduling in production
|
// Check for automatic backup every hour
|
||||||
// Schedule daily backup at 2:00 AM (0 2 * * * means: minute=0, hour=2, any day, any month, any weekday)
|
const checkBackupNeeded = async () => {
|
||||||
cron.schedule('0 2 * * *', async () => {
|
|
||||||
try {
|
try {
|
||||||
console.log('🔄 Starting automatic backup...');
|
const now = new Date();
|
||||||
await this.createBackup('automatic', 'system');
|
const today = now.toISOString().split('T')[0]; // YYYY-MM-DD format
|
||||||
console.log('✅ Automatic backup completed');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('❌ Automatic backup failed:', error);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
timezone: "Europe/Paris" // Adjust timezone as needed
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('⏰ Automatic backup scheduled for 2:00 AM daily (node-cron)');
|
// Only run automatic backup if:
|
||||||
|
// 1. It's after 2:00 AM
|
||||||
|
// 2. We haven't done an automatic backup today yet
|
||||||
|
if (now.getHours() >= 2 && this.lastAutomaticBackupDate !== today) {
|
||||||
|
// Check if there's already an automatic backup today in the database
|
||||||
|
const existingBackupToday = await db.select()
|
||||||
|
.from(databaseBackups)
|
||||||
|
.where(eq(databaseBackups.backupType, 'automatic'))
|
||||||
|
.orderBy(desc(databaseBackups.createdAt))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
const lastBackup = existingBackupToday[0];
|
||||||
|
const lastBackupDate = lastBackup ? lastBackup.createdAt.toISOString().split('T')[0] : null;
|
||||||
|
|
||||||
|
// Only proceed if no automatic backup exists for today
|
||||||
|
if (lastBackupDate !== today) {
|
||||||
|
console.log('🔄 Starting automatic backup...');
|
||||||
|
await this.createBackup('automatic', 'system');
|
||||||
|
this.lastAutomaticBackupDate = today;
|
||||||
|
console.log('✅ Automatic backup completed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Automatic backup check failed:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initial check
|
||||||
|
checkBackupNeeded();
|
||||||
|
|
||||||
|
// Check every hour (3600000 ms)
|
||||||
|
setInterval(checkBackupNeeded, 3600000);
|
||||||
|
|
||||||
|
console.log('⏰ Automatic backup scheduled for daily 2:00 AM+ (native timer)');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user