1. 程序整体架构分析
核心设计模式:单例模式 + 命令模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| service_manager.py ├── 配置层 (Configuration Layer) │ ├── 服务定义 (services字典) │ ├── 环境配置 (conda环境路径) │ └── 日志配置 (logging配置) ├── 管理层 (Management Layer) │ ├── ServiceManager类 │ ├── 进程管理 (PID文件持久化) │ └── 状态监控 (进程状态检查) ├── 操作层 (Operation Layer) │ ├── 启动服务 (start_service) │ ├── 停止服务 (stop_service) │ ├── 重启服务 (restart_service) │ └── 状态查看 (status) └── 接口层 (Interface Layer) ├── 命令行参数解析 ├── 信号处理 └── 用户交互
|
2. 核心组件详解
2.1 配置层设计
1 2 3 4 5 6 7 8 9 10
| self.services = { 'service_name': { 'command': 'script.py', 'port': 8000, 'log_file': './logs/service.log', 'description': '服务描述', 'env': 'conda_env_name' } }
|
设计原则:
- 配置与代码分离:所有服务配置集中在一个字典中
- 可扩展性:添加新服务只需在字典中添加配置
- 可维护性:每个服务的配置项清晰明确
2.2 管理层设计
1 2 3 4 5 6 7 8 9 10 11
| class ServiceManager: def __init__(self): self.services = {...} self.processes = {} self.pid_file = 'service_pids.json' self.load_pids()
|
核心思想:
- 状态持久化:进程PID保存到文件,重启后仍能管理
- 状态同步:内存状态与磁盘状态保持一致
2.3 操作层设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| def start_service(self, service_name: str, force: bool = False) -> bool: if service_name not in self.services: return False if self.is_service_running(service_name) and not force: return True env_path = self.get_conda_env_path(service['env']) log_path = self.prepare_log_directory(service['log_file']) process = self.spawn_process(service, env_path, log_path) if process.is_running(): self.processes[service_name] = process.pid self.save_pids() return True return False
|
操作模式:
- 验证 → 检查 → 准备 → 执行 → 更新
- 每个步骤都有明确的职责和错误处理
3. 如何独立写出这种程序
3.1 第一步:明确需求
1 2 3 4 5 6
| 需求 = { "功能": ["启动服务", "停止服务", "重启服务", "查看状态"], "特性": ["批量操作", "状态持久化", "日志管理", "错误处理"], "接口": ["命令行", "配置文件", "日志输出"] }
|
3.2 第二步:设计数据结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ServiceConfig = { "name": str, "command": str, "port": int, "log_file": str, "env": str, "description": str }
ProcessState = { "pid": int, "start_time": str, "status": str }
|
3.3 第三步:实现核心类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class ServiceManager: def __init__(self, config_file: str = None): """初始化服务管理器""" self.config = self.load_config(config_file) self.processes = {} self.state_file = "service_state.json" self.load_state() def load_config(self, config_file: str) -> dict: """加载配置文件""" pass def load_state(self): """加载进程状态""" pass def save_state(self): """保存进程状态""" pass
|
3.4 第四步:实现核心操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class ServiceManager: def start_service(self, service_name: str) -> bool: """启动服务""" pass def stop_service(self, service_name: str) -> bool: """停止服务""" pass def get_service_status(self, service_name: str) -> dict: """获取服务状态""" pass
|
3.5 第五步:实现命令行接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| def main(): """主函数""" import argparse parser = argparse.ArgumentParser(description="服务管理工具") parser.add_argument("action", choices=["start", "stop", "restart", "status"]) parser.add_argument("service", nargs="?", help="服务名称") parser.add_argument("--all", action="store_true", help="操作所有服务") args = parser.parse_args() manager = ServiceManager() if args.action == "start": if args.all: manager.start_all() else: manager.start_service(args.service)
|
4. 关键设计模式
4.1 状态机模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class ServiceState: STOPPED = "stopped" STARTING = "starting" RUNNING = "running" STOPPING = "stopping" ERROR = "error"
class Service: def __init__(self): self.state = ServiceState.STOPPED def start(self): if self.state == ServiceState.RUNNING: return False self.state = ServiceState.STARTING self.state = ServiceState.RUNNING
|
4.2 观察者模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class ServiceObserver: def on_service_started(self, service_name: str): pass def on_service_stopped(self, service_name: str): pass def on_service_error(self, service_name: str, error: str): pass
class ServiceManager: def __init__(self): self.observers = [] def add_observer(self, observer: ServiceObserver): self.observers.append(observer) def notify_started(self, service_name: str): for observer in self.observers: observer.on_service_started(service_name)
|
4.3 工厂模式
1 2 3 4 5 6 7 8 9 10 11
| class ServiceFactory: @staticmethod def create_service(service_type: str, config: dict): if service_type == "python": return PythonService(config) elif service_type == "node": return NodeService(config) elif service_type == "java": return JavaService(config) else: raise ValueError(f"Unknown service type: {service_type}")
|
5. 扩展功能设计
5.1 配置文件支持
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| services: web_server: command: "python app.py" port: 8000 env: "web_env" auto_restart: true health_check: "http://localhost:8000/health" database: command: "mongod" port: 27017 env: "db_env" auto_restart: false
|
5.2 健康检查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class HealthChecker: def check_service_health(self, service_name: str) -> bool: service = self.services[service_name] if not self.is_process_running(service['pid']): return False if not self.is_port_listening(service['port']): return False if service.get('health_check'): return self.check_health_endpoint(service['health_check']) return True
|
5.3 自动重启
1 2 3 4 5 6 7 8 9 10 11 12 13
| class AutoRestartManager: def __init__(self): self.failed_services = {} self.max_retries = 3 def handle_service_failure(self, service_name: str): if service_name not in self.failed_services: self.failed_services[service_name] = 0 self.failed_services[service_name] += 1 if self.failed_services[service_name] <= self.max_retries: self.restart_service(service_name)
|
6. 测试策略
6.1 单元测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import unittest from unittest.mock import Mock, patch
class TestServiceManager(unittest.TestCase): def setUp(self): self.manager = ServiceManager() @patch('subprocess.Popen') def test_start_service(self, mock_popen): mock_process = Mock() mock_process.poll.return_value = None mock_process.pid = 12345 mock_popen.return_value = mock_process result = self.manager.start_service("test_service") self.assertTrue(result)
|
6.2 集成测试
1 2 3 4 5 6 7 8 9
| class IntegrationTest(unittest.TestCase): def test_full_lifecycle(self): self.manager.start_service("test_service") self.assertTrue(self.manager.is_service_running("test_service")) self.manager.stop_service("test_service") self.assertFalse(self.manager.is_service_running("test_service"))
|
7. 最佳实践总结
7.1 代码组织
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| service_manager/ ├── __init__.py ├── core/ │ ├── __init__.py │ ├── manager.py # 核心管理类 │ ├── config.py # 配置管理 │ └── state.py # 状态管理 ├── services/ │ ├── __init__.py │ ├── base.py # 服务基类 │ ├── python.py # Python服务 │ └── node.py # Node服务 ├── utils/ │ ├── __init__.py │ ├── process.py # 进程工具 │ └── network.py # 网络工具 ├── cli.py # 命令行接口 └── config.yaml # 配置文件
|
7.2 错误处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class ServiceError(Exception): pass
class ServiceNotFoundError(ServiceError): pass
class ServiceStartError(ServiceError): pass
class ServiceStopError(ServiceError): pass
def start_service(self, service_name: str) -> bool: try: if service_name not in self.services: raise ServiceNotFoundError(f"Service {service_name} not found") return True except Exception as e: logger.error(f"Failed to start service {service_name}: {e}") return False
|
7.3 日志管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import logging from logging.handlers import RotatingFileHandler
def setup_logging(): logger = logging.getLogger('service_manager') logger.setLevel(logging.INFO) file_handler = RotatingFileHandler( 'service_manager.log', maxBytes=10*1024*1024, backupCount=5 ) console_handler = logging.StreamHandler() formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) file_handler.setFormatter(formatter) console_handler.setFormatter(formatter) logger.addHandler(file_handler) logger.addHandler(console_handler) return logger
|
通过这种系统性的设计,你可以构建出功能强大、易于维护的服务管理程序。关键是要理解每个组件的职责,以及它们之间如何协作。