#!/bin/bash # Restore script for market data infrastructure # Usage: ./restore.sh set -e # Check if backup file is provided if [ $# -eq 0 ]; then echo "โŒ Usage: $0 " echo "Available backups:" ls -la ./backups/market_data_backup_*.tar.gz 2>/dev/null || echo "No backups found" exit 1 fi BACKUP_FILE="$1" RESTORE_DIR="./restore_temp" TIMESTAMP=$(date +"%Y%m%d_%H%M%S") # Load environment variables if [ -f .env ]; then source .env fi echo "๐Ÿ”„ Starting restore process..." echo "๐Ÿ“ Backup file: $BACKUP_FILE" # Check if backup file exists if [ ! -f "$BACKUP_FILE" ]; then echo "โŒ Backup file not found: $BACKUP_FILE" exit 1 fi # Create temporary restore directory mkdir -p "$RESTORE_DIR" # Extract backup echo "๐Ÿ“ฆ Extracting backup..." tar -xzf "$BACKUP_FILE" -C "$RESTORE_DIR" # Find extracted files TIMESCALE_BACKUP=$(find "$RESTORE_DIR" -name "timescaledb_backup_*.dump" | head -1) REDIS_BACKUP=$(find "$RESTORE_DIR" -name "redis_backup_*.rdb" | head -1) BACKUP_INFO=$(find "$RESTORE_DIR" -name "backup_*.info" | head -1) if [ -z "$TIMESCALE_BACKUP" ] || [ -z "$REDIS_BACKUP" ]; then echo "โŒ Invalid backup file structure" rm -rf "$RESTORE_DIR" exit 1 fi # Display backup information if [ -f "$BACKUP_INFO" ]; then echo "๐Ÿ“‹ Backup Information:" cat "$BACKUP_INFO" echo "" fi # Confirm restore read -p "โš ๏ธ This will replace all existing data. Continue? (y/N): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo "โŒ Restore cancelled" rm -rf "$RESTORE_DIR" exit 1 fi # Stop services echo "๐Ÿ›‘ Stopping services..." docker-compose -f timescaledb-compose.yml down # Backup current data (just in case) echo "๐Ÿ’พ Creating safety backup of current data..." mkdir -p "./backups/pre_restore_$TIMESTAMP" docker run --rm -v market_data_timescale_data:/data -v "$(pwd)/backups/pre_restore_$TIMESTAMP":/backup alpine tar czf /backup/current_timescale.tar.gz -C /data . docker run --rm -v market_data_redis_data:/data -v "$(pwd)/backups/pre_restore_$TIMESTAMP":/backup alpine tar czf /backup/current_redis.tar.gz -C /data . # Start only TimescaleDB for restore echo "๐Ÿƒ Starting TimescaleDB for restore..." docker-compose -f timescaledb-compose.yml up -d timescaledb # Wait for TimescaleDB to be ready echo "โณ Waiting for TimescaleDB to be ready..." sleep 30 # Check if TimescaleDB is ready if ! docker exec market_data_timescaledb pg_isready -U market_user -d market_data; then echo "โŒ TimescaleDB is not ready" exit 1 fi # Drop existing database and recreate echo "๐Ÿ—‘๏ธ Dropping existing database..." docker exec market_data_timescaledb psql -U postgres -c "DROP DATABASE IF EXISTS market_data;" docker exec market_data_timescaledb psql -U postgres -c "CREATE DATABASE market_data OWNER market_user;" # Restore TimescaleDB echo "๐Ÿ“Š Restoring TimescaleDB..." docker cp "$TIMESCALE_BACKUP" market_data_timescaledb:/tmp/restore.dump docker exec market_data_timescaledb pg_restore \ -U market_user \ -d market_data \ --verbose \ --no-password \ /tmp/restore.dump if [ $? -eq 0 ]; then echo "โœ… TimescaleDB restore completed" else echo "โŒ TimescaleDB restore failed" exit 1 fi # Stop TimescaleDB docker-compose -f timescaledb-compose.yml stop timescaledb # Restore Redis data echo "๐Ÿ“ฆ Restoring Redis data..." # Remove existing Redis data docker volume rm market_data_redis_data 2>/dev/null || true docker volume create market_data_redis_data # Copy Redis backup to volume docker run --rm -v market_data_redis_data:/data -v "$(pwd)/$RESTORE_DIR":/backup alpine cp "/backup/$(basename "$REDIS_BACKUP")" /data/dump.rdb # Start all services echo "๐Ÿƒ Starting all services..." docker-compose -f timescaledb-compose.yml up -d # Wait for services to be ready echo "โณ Waiting for services to be ready..." sleep 30 # Verify restore echo "๐Ÿ” Verifying restore..." # Check TimescaleDB if docker exec market_data_timescaledb pg_isready -U market_user -d market_data; then echo "โœ… TimescaleDB is ready" # Show table counts echo "๐Ÿ“Š Database table counts:" docker exec market_data_timescaledb psql -U market_user -d market_data -c " SELECT schemaname, tablename, n_tup_ins as row_count FROM pg_stat_user_tables WHERE schemaname = 'market_data' ORDER BY tablename; " else echo "โŒ TimescaleDB verification failed" exit 1 fi # Check Redis if docker exec market_data_redis redis-cli -a "$REDIS_PASSWORD" ping | grep -q PONG; then echo "โœ… Redis is ready" # Show Redis info echo "๐Ÿ“ฆ Redis database info:" docker exec market_data_redis redis-cli -a "$REDIS_PASSWORD" INFO keyspace else echo "โŒ Redis verification failed" exit 1 fi # Clean up echo "๐Ÿงน Cleaning up temporary files..." rm -rf "$RESTORE_DIR" echo "" echo "๐ŸŽ‰ Restore completed successfully!" echo "" echo "๐Ÿ“‹ Restore Summary:" echo " Source: $BACKUP_FILE" echo " Timestamp: $TIMESTAMP" echo " Safety backup: ./backups/pre_restore_$TIMESTAMP/" echo "" echo "โš ๏ธ If you encounter any issues, you can restore the safety backup:" echo " docker-compose -f timescaledb-compose.yml down" echo " docker volume rm market_data_timescale_data market_data_redis_data" echo " docker volume create market_data_timescale_data" echo " docker volume create market_data_redis_data" echo " docker run --rm -v market_data_timescale_data:/data -v $(pwd)/backups/pre_restore_$TIMESTAMP:/backup alpine tar xzf /backup/current_timescale.tar.gz -C /data" echo " docker run --rm -v market_data_redis_data:/data -v $(pwd)/backups/pre_restore_$TIMESTAMP:/backup alpine tar xzf /backup/current_redis.tar.gz -C /data" echo " docker-compose -f timescaledb-compose.yml up -d"