#!/usr/bin/env node /** * Скрипт для автоматического бэкапа MongoDB * Использование: node scripts/backup.js * Или добавить в cron: 0 2 * * * node /path/to/scripts/backup.js */ const { execSync } = require('child_process'); const fs = require('fs'); const path = require('path'); const dotenv = require('dotenv'); // Загрузить переменные окружения dotenv.config({ path: path.join(__dirname, '../.env') }); const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/nakama'; const BACKUP_DIR = process.env.BACKUP_DIR || path.join(__dirname, '../backups'); const MAX_BACKUPS = parseInt(process.env.MAX_BACKUPS || '30'); // Хранить 30 бэкапов // Парсинг MongoDB URI для получения имени базы данных function getDatabaseName(uri) { try { const match = uri.match(/\/([^/?]+)/); return match ? match[1] : 'nakama'; } catch { return 'nakama'; } } // Парсинг MongoDB URI для получения хоста и порта function getMongoHost(uri) { try { const url = new URL(uri); return `${url.hostname}:${url.port || 27017}`; } catch { return 'localhost:27017'; } } // Создать директорию для бэкапов if (!fs.existsSync(BACKUP_DIR)) { fs.mkdirSync(BACKUP_DIR, { recursive: true }); } // Имя базы данных const dbName = getDatabaseName(MONGODB_URI); const mongoHost = getMongoHost(MONGODB_URI); // Имя файла бэкапа const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const backupName = `backup-${dbName}-${timestamp}`; const backupPath = path.join(BACKUP_DIR, backupName); console.log(`📦 Создание бэкапа базы данных: ${dbName}`); console.log(`📁 Путь: ${backupPath}`); console.log(`🖥️ Хост: ${mongoHost}`); try { // Создать бэкап с помощью mongodump const command = `mongodump --host ${mongoHost} --db ${dbName} --out ${backupPath}`; console.log(`🔄 Выполнение команды: ${command}`); execSync(command, { stdio: 'inherit' }); console.log(`✅ Бэкап создан успешно: ${backupPath}`); // Архивировать бэкап const archivePath = `${backupPath}.tar.gz`; console.log(`📦 Архивирование бэкапа...`); execSync(`tar -czf ${archivePath} -C ${BACKUP_DIR} ${backupName}`, { stdio: 'inherit' }); // Удалить неархивированную директорию execSync(`rm -rf ${backupPath}`, { stdio: 'inherit' }); console.log(`✅ Архив создан: ${archivePath}`); // Удалить старые бэкапы const backups = fs.readdirSync(BACKUP_DIR) .filter(file => file.startsWith(`backup-${dbName}-`) && file.endsWith('.tar.gz')) .map(file => ({ name: file, path: path.join(BACKUP_DIR, file), time: fs.statSync(path.join(BACKUP_DIR, file)).mtime })) .sort((a, b) => b.time - a.time); if (backups.length > MAX_BACKUPS) { const toDelete = backups.slice(MAX_BACKUPS); console.log(`🗑️ Удаление старых бэкапов (${toDelete.length} файлов)...`); toDelete.forEach(backup => { fs.unlinkSync(backup.path); console.log(` Удален: ${backup.name}`); }); } console.log(`✅ Бэкап завершен успешно`); console.log(`📊 Всего бэкапов: ${backups.length}`); } catch (error) { console.error(`❌ Ошибка создания бэкапа:`, error.message); process.exit(1); }