Python脚本如何按需同步业务模块数据

wen python案例 24

本文目录导读:

Python脚本如何按需同步业务模块数据

  1. 基于配置驱动的同步方案
  2. 带依赖管理的同步方案
  3. 带缓存和断点续传的同步方案
  4. 命令行调用示例
  5. 使用建议

我来为你介绍几种按需同步业务模块数据的Python实现方案:

基于配置驱动的同步方案

import json
import time
from typing import Dict, List, Optional
from datetime import datetime
import logging
class BusinessDataSync:
    """业务数据同步器"""
    def __init__(self, config_file: str = 'sync_config.json'):
        self.logger = logging.getLogger(__name__)
        self.config = self.load_config(config_file)
        self.sync_history = []
    def load_config(self, config_file: str) -> Dict:
        """加载同步配置"""
        with open(config_file, 'r', encoding='utf-8') as f:
            return json.load(f)
    def sync_module(self, module_name: str, sync_type: str = 'incremental'):
        """同步指定模块
        Args:
            module_name: 模块名称
            sync_type: 同步类型 (full/incremental)
        """
        if module_name not in self.config['modules']:
            self.logger.error(f"未找到模块: {module_name}")
            return False
        module_config = self.config['modules'][module_name]
        # 获取数据源
        source_data = self._get_source_data(module_config, sync_type)
        # 数据转换
        transformed_data = self._transform_data(source_data, module_config)
        # 写入目标
        success = self._write_to_target(transformed_data, module_config)
        # 记录同步历史
        self._record_sync_history(module_name, sync_type, success)
        return success
    def _get_source_data(self, config: Dict, sync_type: str) -> List[Dict]:
        """获取源数据"""
        source_type = config.get('source_type', 'api')
        if source_type == 'api':
            return self._fetch_from_api(config['source_config'])
        elif source_type == 'database':
            return self._fetch_from_db(config['source_config'])
        elif source_type == 'file':
            return self._fetch_from_file(config['source_config'])
        else:
            raise ValueError(f"不支持的数据源类型: {source_type}")
    def _fetch_from_api(self, config: Dict) -> List[Dict]:
        """从API获取数据"""
        import requests
        params = {
            'page_size': config.get('page_size', 100),
            'page': 1
        }
        # 增量同步时添加时间过滤
        if config.get('last_sync_time'):
            params['updated_after'] = config['last_sync_time']
        all_data = []
        while True:
            response = requests.get(config['url'], params=params)
            data = response.json()
            all_data.extend(data.get('items', []))
            if not data.get('has_more'):
                break
            params['page'] += 1
        return all_data
    def _transform_data(self, data: List[Dict], config: Dict) -> List[Dict]:
        """数据转换"""
        mapping = config.get('field_mapping', {})
        transformed = []
        for item in data:
            new_item = {}
            for source_field, target_field in mapping.items():
                new_item[target_field] = item.get(source_field)
            transformed.append(new_item)
        return transformed
    def _write_to_target(self, data: List[Dict], config: Dict) -> bool:
        """写入目标系统"""
        target_type = config.get('target_type', 'database')
        if target_type == 'database':
            return self._write_to_db(data, config['target_config'])
        elif target_type == 'file':
            return self._write_to_file(data, config['target_config'])
        elif target_type == 'redis':
            return self._write_to_redis(data, config['target_config'])
        else:
            raise ValueError(f"不支持的目标类型: {target_type}")
    def _record_sync_history(self, module: str, sync_type: str, success: bool):
        """记录同步历史"""
        self.sync_history.append({
            'module': module,
            'sync_type': sync_type,
            'timestamp': datetime.now().isoformat(),
            'success': success
        })
# 配置文件示例 (sync_config.json)
"""
{
    "modules": {
        "user": {
            "source_type": "api",
            "source_config": {
                "url": "https://api.example.com/users",
                "page_size": 100
            },
            "target_type": "database",
            "target_config": {
                "host": "localhost",
                "database": "business_db",
                "table": "users"
            },
            "field_mapping": {
                "id": "user_id",
                "name": "username",
                "email": "email"
            }
        },
        "order": {
            "source_type": "api",
            "source_config": {
                "url": "https://api.example.com/orders",
                "page_size": 50
            },
            "target_type": "file",
            "target_config": {
                "path": "/data/orders/",
                "format": "json"
            },
            "field_mapping": {
                "order_id": "id",
                "total_amount": "amount"
            }
        }
    }
}
"""
# 使用示例
sync = BusinessDataSync('sync_config.json')
# 按需同步用户模块
sync.sync_module('user', 'incremental')
# 全量同步订单模块
sync.sync_module('order', 'full')

带依赖管理的同步方案

from typing import Dict, List, Set
from enum import Enum
class SyncStatus(Enum):
    PENDING = 'pending'
    SYNCING = 'syncing'
    COMPLETED = 'completed'
    FAILED = 'failed'
class DependencySyncManager:
    """依赖同步管理器"""
    def __init__(self):
        self.dependencies = {
            'user': [],           # 用户模块无依赖
            'order': ['user'],    # 订单模块依赖用户
            'product': ['category'],  # 产品模块依赖分类
            'category': [],       # 分类模块无依赖
            'inventory': ['product', 'warehouse'],  # 库存依赖产品和仓库
            'warehouse': []
        }
        self.module_status = {}
        self.sync_handlers = {}
    def register_handler(self, module: str, handler_func):
        """注册同步处理器"""
        self.sync_handlers[module] = handler_func
    def get_sync_order(self, modules: List[str]) -> List[str]:
        """获取同步顺序(拓扑排序)"""
        from collections import deque
        # 计算入度
        in_degree = {m: 0 for m in modules}
        graph = {m: [] for m in modules}
        for module in modules:
            for dep in self.dependencies.get(module, []):
                if dep in modules:
                    in_degree[module] = in_degree.get(module, 0) + 1
                    graph[dep].append(module)
        # BFS拓扑排序
        queue = deque([m for m in modules if in_degree[m] == 0])
        sorted_modules = []
        while queue:
            module = queue.popleft()
            sorted_modules.append(module)
            for next_module in graph[module]:
                in_degree[next_module] -= 1
                if in_degree[next_module] == 0:
                    queue.append(next_module)
        # 检查是否有循环依赖
        if len(sorted_modules) != len(modules):
            raise ValueError("检测到循环依赖关系")
        return sorted_modules
    def sync_modules_with_dependencies(self, modules: List[str]):
        """同步指定模块及其依赖"""
        # 获取所有需要同步的模块(包括依赖)
        modules_to_sync = set()
        for module in modules:
            modules_to_sync.add(module)
            modules_to_sync.update(self._get_all_dependencies(module))
        # 获取同步顺序
        sync_order = self.get_sync_order(list(modules_to_sync))
        results = {}
        print(f"同步顺序: {sync_order}")
        for module in sync_order:
            print(f"正在同步模块: {module}")
            self.module_status[module] = SyncStatus.SYNCING
            try:
                if module in self.sync_handlers:
                    result = self.sync_handlers[module]()
                    results[module] = result
                    self.module_status[module] = SyncStatus.COMPLETED
                    print(f"模块 {module} 同步完成")
                else:
                    raise ValueError(f"未找到模块 {module} 的同步处理器")
            except Exception as e:
                self.module_status[module] = SyncStatus.FAILED
                print(f"模块 {module} 同步失败: {e}")
                results[module] = None
        return results
    def _get_all_dependencies(self, module: str) -> Set[str]:
        """获取模块的所有依赖(递归)"""
        dependencies = set()
        for dep in self.dependencies.get(module, []):
            if dep not in dependencies:
                dependencies.add(dep)
                dependencies.update(self._get_all_dependencies(dep))
        return dependencies
# 使用示例
def sync_user_module():
    print("执行用户数据同步...")
    return {"synced_records": 100}
def sync_order_module():
    print("执行订单数据同步...")
    return {"synced_records": 200}
def sync_product_module():
    print("执行产品数据同步...")
    return {"synced_records": 50}
# 初始化管理器
manager = DependencySyncManager()
manager.register_handler('user', sync_user_module)
manager.register_handler('order', sync_order_module)
manager.register_handler('product', sync_product_module)
manager.register_handler('category', lambda: {"synced_records": 30})
# 按需同步(自动处理依赖)
results = manager.sync_modules_with_dependencies(['order', 'product'])
print(f"同步结果: {results}")

带缓存和断点续传的同步方案

import pickle
import hashlib
from datetime import datetime, timedelta
class CacheSyncManager:
    """带缓存的同步管理器"""
    def __init__(self, cache_dir: str = './sync_cache'):
        import os
        self.cache_dir = cache_dir
        os.makedirs(cache_dir, exist_ok=True)
        self.cache_ttl = {
            'user': timedelta(hours=1),
            'order': timedelta(minutes=30),
            'product': timedelta(days=1)
        }
    def get_cache_key(self, module: str, params: Dict = None) -> str:
        """生成缓存键"""
        base_key = f"sync_{module}"
        if params:
            param_str = json.dumps(params, sort_keys=True)
            base_key = f"{base_key}_{hashlib.md5(param_str.encode()).hexdigest()[:8]}"
        return base_key
    def get_cached_data(self, module: str, params: Dict = None) -> Optional[List[Dict]]:
        """获取缓存数据"""
        cache_key = self.get_cache_key(module, params)
        cache_file = f"{self.cache_dir}/{cache_key}.pkl"
        try:
            with open(cache_file, 'rb') as f:
                cached_data = pickle.load(f)
            # 检查缓存有效期
            if datetime.now() - cached_data['timestamp'] < self.cache_ttl.get(module, timedelta(hours=1)):
                return cached_data['data']
        except (FileNotFoundError, pickle.UnpicklingError):
            pass
        return None
    def set_cached_data(self, module: str, data: List[Dict], params: Dict = None):
        """设置缓存数据"""
        cache_key = self.get_cache_key(module, params)
        cache_file = f"{self.cache_dir}/{cache_key}.pkl"
        cached_data = {
            'timestamp': datetime.now(),
            'data': data,
            'module': module
        }
        with open(cache_file, 'wb') as f:
            pickle.dump(cached_data, f)
    def sync_with_checkpoint(self, module: str, batch_size: int = 100):
        """带检查点的同步(支持断点续传)"""
        checkpoint_file = f"{self.cache_dir}/checkpoint_{module}.json"
        # 检查是否有检查点
        checkpoint = self._load_checkpoint(checkpoint_file)
        start_id = checkpoint.get('last_processed_id', 0) if checkpoint else 0
        print(f"从ID {start_id} 继续同步模块 {module}")
        processed_count = 0
        has_more = True
        while has_more:
            try:
                # 分批获取数据
                batch_data = self._fetch_batch(module, start_id, batch_size)
                if not batch_data:
                    has_more = False
                    break
                # 处理批次数据
                self._process_batch(module, batch_data)
                # 更新检查点
                last_id = batch_data[-1].get('id')
                self._save_checkpoint(checkpoint_file, {
                    'last_processed_id': last_id,
                    'processed_count': processed_count + len(batch_data),
                    'last_update': datetime.now().isoformat()
                })
                processed_count += len(batch_data)
                start_id = last_id
                print(f"已同步 {processed_count} 条记录")
            except Exception as e:
                print(f"同步中断于ID {start_id}: {e}")
                return {
                    'success': False,
                    'processed_count': processed_count,
                    'next_checkpoint': start_id
                }
        # 同步完成,删除检查点
        import os
        os.remove(checkpoint_file)
        return {
            'success': True,
            'processed_count': processed_count
        }
    def _load_checkpoint(self, filepath: str) -> Optional[Dict]:
        """加载检查点"""
        try:
            with open(filepath, 'r') as f:
                return json.load(f)
        except FileNotFoundError:
            return None
    def _save_checkpoint(self, filepath: str, checkpoint: Dict):
        """保存检查点"""
        with open(filepath, 'w') as f:
            json.dump(checkpoint, f)
    def _fetch_batch(self, module: str, start_id: int, batch_size: int) -> List[Dict]:
        """分批获取数据"""
        # 模拟数据库查询
        import random
        return [
            {'id': start_id + i, 'data': f'data_{i}'}
            for i in range(batch_size)
            if random.random() > 0.1  # 模拟数据终止
        ]
    def _process_batch(self, module: str, batch_data: List[Dict]):
        """处理批次数据"""
        # 实际应用中的业务处理
        pass
# 使用示例
cache_manager = CacheSyncManager()
# 检查缓存
cached_users = cache_manager.get_cached_data('user')
if cached_users:
    print("使用缓存数据")
else:
    print("缓存过期或不存在,执行同步")
    # 执行同步逻辑
    new_data = [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]
    cache_manager.set_cached_data('user', new_data)
# 断点续传同步
result = cache_manager.sync_with_checkpoint('order', batch_size=50)
print(f"同步结果: {result}")

命令行调用示例

import argparse
import sys
def main():
    parser = argparse.ArgumentParser(description='业务数据同步工具')
    parser.add_argument('--modules', nargs='+', required=True, help='需要同步的模块')
    parser.add_argument('--sync-type', choices=['full', 'incremental'], default='incremental')
    parser.add_argument('--config', default='sync_config.json', help='配置文件路径')
    parser.add_argument('--parallel', action='store_true', help='是否并行同步')
    parser.add_argument('--force', action='store_true', help='强制重新同步')
    args = parser.parse_args()
    # 初始化同步器
    from concurrent.futures import ThreadPoolExecutor
    if args.parallel:
        # 并行同步
        with ThreadPoolExecutor(max_workers=5) as executor:
            futures = []
            for module in args.modules:
                future = executor.submit(
                    sync_module_wrapper,
                    module,
                    args.sync_type,
                    args.config,
                    args.force
                )
                futures.append(future)
            for future in futures:
                result = future.result()
                print(f"同步结果: {result}")
    else:
        # 串行同步
        for module in args.modules:
            result = sync_module_wrapper(module, args.sync_type, args.config, args.force)
            print(f"模块 {module} 同步 {'成功' if result else '失败'}")
def sync_module_wrapper(module, sync_type, config, force):
    """同步模块包装函数"""
    sync = BusinessDataSync(config)
    return sync.sync_module(module, sync_type)
if __name__ == '__main__':
    main()

使用命令行调用:

# 同步指定模块
python sync.py --modules user order product
# 全量同步
python sync.py --modules user --sync-type full
# 并行同步
python sync.py --modules user order product --parallel
# 强制重新同步
python sync.py --modules user --force

使用建议

  1. 选择合适的同步策略

    • 全量同步:首次同步或数据一致性要求高时使用
    • 增量同步:日常数据更新,效率更高
    • 基于时间戳或版本号的增量同步
  2. 错误处理

    • 实现重试机制,支持断点续传
    • 记录同步日志,便于排查问题
    • 设置同步超时时间
  3. 性能优化

    • 使用缓存减少重复同步
    • 批量处理大数量数据
    • 考虑并行同步非依赖模块
  4. 监控告警

    • 监控同步状态和延迟
    • 同步失败时发送通知
    • 定期检查数据一致性

这些方案可以根据你的具体业务需求进行调整和扩展。

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