""" 服务管理包。用这个包能根据服务的名称启动服务。 """ import importlib import os.path from types import ModuleType from typing import Callable, Awaitable import pandas as pd from paste.core import aio_pool, config from paste.core.logging import logger_config_name from paste.util import ufile, udict service_flag = ['service_name', 'pid_file', 'start_service', 'start', 'stop'] """ 模块若要成为服务,必须同时具备以上属性。 """ def get_services(full_log_path=True): """ 取得所有服务列表及其运行状态,返回格式为 Pandas DataFrame。 :param full_log_path: 是否输出完整日志文件路径 :return: 服务运行状态数据框架 """ _service_info = [] _service_module = 'service' _service_path = os.path.join(os.path.curdir, _service_module) for _root, _dirs, _files in os.walk(_service_path): for _file in _files: _file_name, _ = os.path.splitext(_file) if not _file_name.endswith('_service'): continue _mod_name = '.'.join([_service_module, _file_name]) _service_info.append(read_service_info(_mod_name, full_log_path)) _service_df = pd.DataFrame(_service_info) return _service_df def is_service(service_module: ModuleType): """ 检查模块是否是服务模块。 :param service_module: :return: """ _is_service = True for _attr in service_flag: if hasattr(service_module, _attr): continue _is_service = False return _is_service def read_service_info(full_module_name: str, full_log_path=True): """ 读取模块信息。 :param full_module_name: 完整模块路径 :param full_log_path: 是否输出完整日志文件路径 :return: 服务模块信息 """ _module = importlib.import_module(full_module_name) assert is_service(_module), f"未设置关键属性,请确认是否为服务." _pid = '' _process_info = {} _is_running = False if os.path.exists(_module.pid_file): _pid = ufile.read_to_buffer(_module.pid_file).decode('utf8').strip() _process_info = aio_pool.process_info(int(_pid)) _is_running = True if _process_info else False _configure = config.load_config() _logger_config_name = getattr(_module, 'logger_config_name', logger_config_name) if full_log_path: _logger_file_path = os.path.abspath(udict.get_by_path(_configure, f"{_logger_config_name}.filename")) else: _logger_file_path = udict.get_by_path(_configure, f"{_logger_config_name}.filename") # 代码中的 service_name 在这里作为服务描述 # 而 full_module_name 作为服务名称 _info = { 'service': full_module_name, 'service_name': _module.service_name, 'is_running': os.path.exists(_module.pid_file), 'logger_config_name': _logger_config_name, 'logger_file_path': _logger_file_path, 'pid_file': _module.pid_file, 'pid': _pid, 'process_name': _process_info.get('name', '') if _process_info else '', 'cpu_usage': _process_info.get('cpu_usage', '') if _process_info else '', 'memory_usage': _process_info.get('memory_usage', '') if _process_info else '', 'running_time': _process_info.get('running_time', '') if _process_info else '', } return _info def start_service(full_module_name: str): """ 在控制台启动服务,注意:当控制台关闭时,服务随即停止。 :param full_module_name: 完整模块路径。 :return: 操作状态,仅代表操作状态,并非立即启动服务 """ _module = importlib.import_module(full_module_name) _start: Callable = getattr(_module, 'start_service', None) if not isinstance(_start, Callable): return _result = _start() # 处理异步方法执行 if isinstance(_result, Awaitable): _runner = aio_pool.get_aio_runner() _result = _runner(_result) def start(full_module_name: str): """ 启动服务。 :param full_module_name: 完整模块路径。 :return: 操作状态,仅代表操作状态,并非立即启动服务 """ _module = importlib.import_module(full_module_name) _start: Callable = getattr(_module, 'start', None) if not isinstance(_start, Callable): return _result = _start() # 处理异步方法执行 if isinstance(_result, Awaitable): _runner = aio_pool.get_aio_runner() _result = _runner(_result) def stop(full_module_name: str): """ 停止服务。 :param full_module_name: 完整模块路径。 :return: 操作状态,仅代表操作状态,并非立即结束服务 """ _module = importlib.import_module(full_module_name) _stop: Callable = getattr(_module, 'stop', None) if not isinstance(_stop, Callable): return _result = _stop() # 处理异步方法执行 if isinstance(_result, Awaitable): _runner = aio_pool.get_aio_runner() _result = _runner(_result)