Python脚本如何自动化修复同步常规异常

wen python案例 30

本文目录导读:

Python脚本如何自动化修复同步常规异常

  1. 基础同步异常修复框架
  2. 常见异常检测与修复
  3. 网络同步修复
  4. 自动修复流程
  5. 监控与自动执行

我来分享一个Python自动化修复同步异常的脚本方案,涵盖常见的同步问题处理。

基础同步异常修复框架

import os
import sys
import time
import shutil
import logging
import hashlib
import subprocess
from datetime import datetime
from pathlib import Path
import json
# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('sync_fix.log'),
        logging.StreamHandler()
    ]
)
class SyncRepairTool:
    def __init__(self, config_path='sync_config.json'):
        self.config = self.load_config(config_path)
        self.fix_history = []
    def load_config(self, config_path):
        """加载配置文件"""
        try:
            with open(config_path, 'r', encoding='utf-8') as f:
                return json.load(f)
        except FileNotFoundError:
            # 默认配置
            return {
                'source_dir': '/path/to/source',
                'target_dir': '/path/to/target',
                'backup_dir': '/path/to/backup',
                'temp_dir': '/tmp/sync_temp',
                'max_retries': 3,
                'timeout': 30
            }
    def create_backup(self, file_path):
        """创建文件备份"""
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        backup_path = Path(self.config['backup_dir']) / f"{file_path.name}.{timestamp}.bak"
        try:
            shutil.copy2(file_path, backup_path)
            logging.info(f"备份创建成功: {backup_path}")
            return backup_path
        except Exception as e:
            logging.error(f"备份失败 {file_path}: {str(e)}")
            return None

常见异常检测与修复

class SyncExceptionHandler:
    """处理常见的同步异常"""
    @staticmethod
    def fix_file_locked(file_path):
        """修复文件被锁定的问题"""
        try:
            # 检查文件是否被其他进程占用
            if os.name == 'nt':  # Windows
                with open(file_path, 'rb') as f:
                    f.read(1)
            else:  # Linux/Mac
                import fcntl
                with open(file_path, 'rb') as f:
                    fcntl.flock(f, fcntl.LOCK_SH | fcntl.LOCK_NB)
                    fcntl.flock(f, fcntl.LOCK_UN)
            return True
        except (IOError, BlockingIOError):
            # 文件被锁定,尝试强制关闭相关进程
            SyncExceptionHandler._force_close_process(file_path)
            time.sleep(2)
            return False
    @staticmethod
    def _force_close_process(file_path):
        """强制关闭占用文件的进程"""
        if os.name == 'nt':
            import psutil
            for proc in psutil.process_iter(['pid', 'name']):
                try:
                    if file_path in [f.path for f in proc.open_files()]:
                        proc.terminate()
                        logging.info(f"终止进程: {proc.name()} (PID: {proc.pid})")
                except (psutil.NoSuchProcess, psutil.AccessDenied):
                    pass
        else:
            subprocess.run(['fuser', '-k', str(file_path)], 
                          capture_output=True, timeout=5)
    @staticmethod
    def fix_permission_error(file_path):
        """修复权限错误"""
        try:
            if os.name == 'nt':
                subprocess.run(['icacls', str(file_path), '/grant', 
                              f'{os.getlogin()}:(F)'], capture_output=True)
            else:
                os.chmod(file_path, 0o644)
                # 修改所有者
                import pwd, grp
                uid = pwd.getpwnam(os.getlogin()).pw_uid
                gid = grp.getgrnam('staff').gr_gid
                os.chown(file_path, uid, gid)
            logging.info(f"权限修复成功: {file_path}")
            return True
        except Exception as e:
            logging.error(f"权限修复失败: {str(e)}")
            return False
    @staticmethod
    def fix_disk_space(target_dir):
        """检查并修复磁盘空间不足问题"""
        try:
            if os.name == 'nt':
                import ctypes
                free_bytes = ctypes.c_ulonglong(0)
                ctypes.windll.kernel32.GetDiskFreeSpaceExW(
                    ctypes.c_wchar_p(target_dir), None, None, 
                    ctypes.pointer(free_bytes))
                free_space = free_bytes.value
            else:
                stat = os.statvfs(target_dir)
                free_space = stat.f_frsize * stat.f_bavail
            min_required = 1 * 1024 * 1024 * 1024  # 1GB最小空间
            if free_space < min_required:
                # 清理临时文件和旧备份
                SyncExceptionHandler._cleanup_old_files(target_dir)
                return False
            return True
        except Exception as e:
            logging.error(f"磁盘空间检查失败: {str(e)}")
            return False
    @staticmethod
    def _cleanup_old_files(directory):
        """清理旧文件释放空间"""
        try:
            # 删除30天前的备份文件
            threshold = time.time() - (30 * 24 * 3600)
            for f in Path(directory).glob('*.bak'):
                if f.stat().st_mtime < threshold:
                    f.unlink()
                    logging.info(f"清理旧备份: {f}")
        except Exception as e:
            logging.error(f"文件清理失败: {str(e)}")

网络同步修复

class NetworkSyncRepair:
    """修复网络同步问题"""
    @staticmethod
    def fix_network_connection(host='8.8.8.8', port=53, timeout=3):
        """修复网络连接问题"""
        import socket
        try:
            # 测试DNS解析
            socket.gethostbyname('google.com')
        except socket.gaierror:
            # DNS问题,尝试刷新DNS缓存
            NetworkSyncRepair._flush_dns_cache()
        # 测试网络连通性
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(timeout)
            result = sock.connect_ex((host, port))
            sock.close()
            return result == 0
        except:
            return False
    @staticmethod
    def _flush_dns_cache():
        """刷新DNS缓存"""
        try:
            if os.name == 'nt':
                subprocess.run(['ipconfig', '/flushdns'], 
                              capture_output=True, timeout=10)
            elif sys.platform == 'darwin':
                subprocess.run(['dscacheutil', '-flushcache'],
                              capture_output=True, timeout=10)
            else:
                subprocess.run(['systemctl', 'restart', 'systemd-resolved'],
                              capture_output=True, timeout=10)
            logging.info("DNS缓存已刷新")
        except Exception as e:
            logging.error(f"DNS刷新失败: {str(e)}")
    @staticmethod
    def fix_sync_service(service_name):
        """修复同步服务"""
        try:
            if os.name == 'nt':
                subprocess.run(['net', 'stop', service_name], 
                              capture_output=True, timeout=30)
                time.sleep(2)
                subprocess.run(['net', 'start', service_name],
                              capture_output=True, timeout=30)
            else:
                subprocess.run(['systemctl', 'restart', service_name],
                              capture_output=True, timeout=30)
            logging.info(f"服务已重启: {service_name}")
            return True
        except Exception as e:
            logging.error(f"服务重启失败: {str(e)}")
            return False

自动修复流程

class AutoSyncRepair:
    """自动化同步修复主程序"""
    def __init__(self, sync_tool):
        self.tool = sync_tool
        self.handler = SyncExceptionHandler()
        self.network = NetworkSyncRepair()
    def repair_sync(self, file_path, error_type='unknown'):
        """执行自动修复流程"""
        logging.info(f"开始修复文件: {file_path} (错误类型: {error_type})")
        # 1. 创建备份
        backup_path = self.tool.create_backup(file_path)
        # 2. 检查常见问题
        fixes_applied = []
        # 2.1 检查网络连接
        if not self.network.fix_network_connection():
            fixes_applied.append('network_fix')
        # 2.2 检查磁盘空间
        if not self.handler.fix_disk_space(self.tool.config['target_dir']):
            fixes_applied.append('disk_space_fix')
        # 2.3 检查文件锁定
        if self.handler.fix_file_locked(file_path):
            fixes_applied.append('file_lock_fix')
        # 2.4 检查权限
        if self.handler.fix_permission_error(file_path):
            fixes_applied.append('permission_fix')
        # 3. 重试同步
        if fixes_applied:
            logging.info(f"应用了修复: {fixes_applied}")
            return self.retry_sync(file_path)
        # 4. 如果常规修复无效,尝试更强力的方法
        return self.force_fix(file_path)
    def retry_sync(self, file_path, max_retries=3):
        """重试同步操作"""
        for attempt in range(max_retries):
            logging.info(f"重试同步 (第 {attempt + 1} 次)")
            try:
                # 模拟同步命令
                result = subprocess.run(
                    ['rsync', '-avz', str(file_path), 
                     str(Path(self.tool.config['target_dir']))],
                    capture_output=True, text=True,
                    timeout=self.tool.config['timeout']
                )
                if result.returncode == 0:
                    logging.info(f"同步成功: {file_path}")
                    return True
            except subprocess.TimeoutExpired:
                logging.warning("同步超时")
                time.sleep(2)
            except Exception as e:
                logging.error(f"同步错误: {str(e)}")
        return False
    def force_fix(self, file_path):
        """强力修复方法"""
        logging.warning("尝试强力修复...")
        try:
            # 1. 计算文件哈希
            hash_md5 = hashlib.md5()
            with open(file_path, 'rb') as f:
                for chunk in iter(lambda: f.read(4096), b''):
                    hash_md5.update(chunk)
            original_hash = hash_md5.hexdigest()
            # 2. 复制到临时目录
            temp_path = Path(self.tool.config['temp_dir']) / file_path.name
            shutil.copy2(file_path, temp_path)
            # 3. 删除原文件
            file_path.unlink()
            # 4. 从临时目录恢复
            shutil.copy2(temp_path, file_path)
            # 5. 验证完整性
            hash_md5 = hashlib.md5()
            with open(file_path, 'rb') as f:
                for chunk in iter(lambda: f.read(4096), b''):
                    hash_md5.update(chunk)
            if hash_md5.hexdigest() == original_hash:
                logging.info("强力修复成功")
                return self.retry_sync(file_path)
            else:
                logging.error("文件完整性验证失败")
                return False
        except Exception as e:
            logging.error(f"强力修复失败: {str(e)}")
            return False

监控与自动执行

class SyncMonitor:
    """同步状态监控器"""
    def __init__(self, repair_tool, check_interval=60):
        self.repair_tool = repair_tool
        self.check_interval = check_interval
        self.failed_syncs = []
    def monitor_and_repair(self):
        """持续监控并自动修复"""
        logging.info("开始同步监控...")
        while True:
            try:
                # 检查同步状态
                sync_status = self.check_sync_status()
                if sync_status['failed']:
                    for failed_item in sync_status['failed']:
                        # 自动修复
                        if failed_item not in self.failed_syncs:
                            success = self.repair_tool.repair_sync(
                                failed_item['path'],
                                failed_item['error']
                            )
                            if not success:
                                self.failed_syncs.append(failed_item)
                                logging.warning(f"需要手动干预: {failed_item['path']}")
                # 清除已成功的修复记录
                self.failed_syncs = [
                    f for f in self.failed_syncs 
                    if not Path(f['path']).exists()
                ]
                time.sleep(self.check_interval)
            except KeyboardInterrupt:
                logging.info("监控已停止")
                break
            except Exception as e:
                logging.error(f"监控错误: {str(e)}")
                time.sleep(self.check_interval)
    def check_sync_status(self):
        """检查同步状态"""
        # 这里应该实现实际的同步状态检查逻辑
        return {
            'failed': [],  # 失败项列表
            'success': [], # 成功项列表
            'pending': []  # 等待项列表
        }
# 使用示例
if __name__ == '__main__':
    # 创建修复工具实例
    repair_tool = AutoSyncRepair(SyncRepairTool())
    # 执行单次修复
    repair_tool.repair_sync(Path('/path/to/problem/file.txt'))
    # 或者启动持续监控
    # monitor = SyncMonitor(repair_tool, check_interval=60)
    # monitor.monitor_and_repair()

这个脚本提供了完善的同步异常修复能力,包括:

  • 文件锁定问题修复
  • 权限错误处理
  • 磁盘空间管理
  • 网络连接修复
  • 服务重启机制
  • 自动重试逻辑
  • 监控与告警

使用时请根据实际的同步环境和需求调整配置参数。

抱歉,评论功能暂时关闭!