postgresql.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. import os
  2. import subprocess
  3. import logging
  4. import time
  5. from pathlib import Path
  6. import shutil
  7. # 配置日志
  8. logging.basicConfig(
  9. level=logging.INFO,
  10. format='%(asctime)s - %(levelname)s - %(message)s',
  11. handlers=[
  12. logging.StreamHandler(),
  13. logging.FileHandler('postgres_service_manager.log')
  14. ]
  15. )
  16. logger = logging.getLogger(__name__)
  17. def get_postgres_service_name():
  18. """获取 PostgreSQL 服务名称"""
  19. service_names = [
  20. "postgresql-x64-16",
  21. "postgresql-x64-15",
  22. "postgresql-x64-14",
  23. "postgresql-x64-13",
  24. "postgresql-x64-12",
  25. "postgresql"
  26. ]
  27. # 检查服务状态
  28. for service in service_names:
  29. try:
  30. result = subprocess.run(
  31. ["sc", "query", service],
  32. capture_output=True,
  33. text=True,
  34. encoding='utf-8',
  35. errors='ignore'
  36. )
  37. if "RUNNING" in result.stdout or "STOPPED" in result.stdout:
  38. return service
  39. except Exception:
  40. continue
  41. return service_names[0] if service_names else "postgresql"
  42. def is_service_running(service_name=None):
  43. """检查服务是否正在运行"""
  44. if not service_name:
  45. service_name = get_postgres_service_name()
  46. try:
  47. result = subprocess.run(
  48. ["sc", "query", service_name],
  49. capture_output=True,
  50. text=True,
  51. encoding='utf-8',
  52. errors='ignore'
  53. )
  54. return "RUNNING" in result.stdout
  55. except Exception as e:
  56. logger.error(f"检查服务状态失败: {str(e)}")
  57. return False
  58. def stop_postgres_service():
  59. """停止 PostgreSQL 服务"""
  60. try:
  61. service_name = get_postgres_service_name()
  62. logger.info(f"尝试停止 PostgreSQL 服务: {service_name}")
  63. # 使用 net stop 停止服务
  64. result = subprocess.run(
  65. ["net", "stop", service_name],
  66. capture_output=True,
  67. text=True,
  68. encoding='utf-8',
  69. errors='ignore'
  70. )
  71. if result.returncode == 0:
  72. logger.info(f"PostgreSQL 服务 '{service_name}' 已停止")
  73. return True
  74. # 如果 net stop 失败,尝试 sc stop
  75. result = subprocess.run(
  76. ["sc", "stop", service_name],
  77. capture_output=True,
  78. text=True,
  79. encoding='utf-8',
  80. errors='ignore'
  81. )
  82. if result.returncode == 0:
  83. logger.info(f"PostgreSQL 服务 '{service_name}' 已停止")
  84. return True
  85. # 如果服务未停止,尝试强制终止进程
  86. logger.warning("服务未正常停止,尝试终止进程")
  87. subprocess.run(
  88. ["taskkill", "/F", "/IM", "postgres.exe"],
  89. capture_output=True,
  90. encoding='utf-8',
  91. errors='ignore'
  92. )
  93. logger.info("PostgreSQL 进程已终止")
  94. return True
  95. except Exception as e:
  96. logger.error(f"停止 PostgreSQL 服务失败: {str(e)}")
  97. return False
  98. def start_postgres_service():
  99. """启动 PostgreSQL 服务"""
  100. try:
  101. service_name = get_postgres_service_name()
  102. logger.info(f"尝试启动 PostgreSQL 服务: {service_name}")
  103. # 使用 net start 启动服务
  104. result = subprocess.run(
  105. ["net", "start", service_name],
  106. capture_output=True,
  107. text=True,
  108. encoding='utf-8',
  109. errors='ignore'
  110. )
  111. if result.returncode == 0:
  112. logger.info(f"PostgreSQL 服务 '{service_name}' 已启动")
  113. return True
  114. # 如果 net start 失败,尝试 sc start
  115. result = subprocess.run(
  116. ["sc", "start", service_name],
  117. capture_output=True,
  118. text=True,
  119. encoding='utf-8',
  120. errors='ignore'
  121. )
  122. if result.returncode == 0:
  123. logger.info(f"PostgreSQL 服务 '{service_name}' 已启动")
  124. return True
  125. raise RuntimeError("启动 PostgreSQL 服务失败")
  126. except Exception as e:
  127. logger.error(f"启动 PostgreSQL 服务失败: {str(e)}")
  128. return False
  129. def restart_postgres_service():
  130. """重启 PostgreSQL 服务"""
  131. try:
  132. if stop_postgres_service():
  133. time.sleep(3) # 等待服务完全停止
  134. return start_postgres_service()
  135. except Exception as e:
  136. logger.error(f"重启 PostgreSQL 服务失败: {str(e)}")
  137. return False
  138. def get_postgres_data_dir():
  139. """获取 PostgreSQL 数据目录"""
  140. possible_paths = [
  141. r"D:/app/postgresql/data",
  142. r"C:/Program Files/PostgreSQL/15/data",
  143. r"C:/Program Files/PostgreSQL/14/data",
  144. r"C:/Program Files/PostgreSQL/13/data",
  145. r"C:/Program Files/PostgreSQL/12/data",
  146. ]
  147. env_path = os.environ.get('PGDATA')
  148. if env_path and Path(env_path).exists():
  149. return Path(env_path)
  150. for path in possible_paths:
  151. if Path(path).exists():
  152. return Path(path)
  153. raise FileNotFoundError("无法找到 PostgreSQL 数据目录")
  154. def fix_postgres_service():
  155. """修复 PostgreSQL 服务启动问题"""
  156. try:
  157. logger.info("开始修复 PostgreSQL 服务启动问题...")
  158. # 1. 停止服务
  159. if not stop_postgres_service():
  160. logger.warning("无法停止服务,尝试强制修复")
  161. # 2. 检查数据目录
  162. try:
  163. data_dir = get_postgres_data_dir()
  164. logger.info(f"找到 PostgreSQL 数据目录: {data_dir}")
  165. # 3. 检查并处理恢复配置文件
  166. recovery_signal = data_dir / "recovery.signal"
  167. recovery_done = data_dir / "recovery.done"
  168. auto_conf = data_dir / "postgresql.auto.conf"
  169. if recovery_signal.exists():
  170. logger.info("发现 recovery.signal 文件,尝试完成恢复过程")
  171. if recovery_done.exists():
  172. recovery_done.unlink()
  173. recovery_signal.rename(recovery_done)
  174. logger.info("已将 recovery.signal 重命名为 recovery.done")
  175. # 4. 删除可能引起问题的自动配置文件
  176. if auto_conf.exists():
  177. backup_auto_conf = auto_conf.with_suffix(".auto.conf.bak")
  178. shutil.copy(auto_conf, backup_auto_conf)
  179. auto_conf.unlink()
  180. logger.info("已备份并删除 postgresql.auto.conf 文件")
  181. # 5. 检查 postgresql.conf 文件
  182. conf_file = data_dir / "postgresql.conf"
  183. if conf_file.exists():
  184. logger.info("检查 postgresql.conf 文件完整性")
  185. # 这里可以添加更多的配置文件检查逻辑
  186. except FileNotFoundError as e:
  187. logger.warning(f"无法找到数据目录: {str(e)}")
  188. # 6. 确保所有 PostgreSQL 进程已终止
  189. subprocess.run(
  190. ["taskkill", "/F", "/IM", "postgres.exe"],
  191. capture_output=True,
  192. encoding='utf-8',
  193. errors='ignore'
  194. )
  195. # 7. 尝试启动服务
  196. time.sleep(2)
  197. if start_postgres_service():
  198. logger.info("PostgreSQL 服务修复成功")
  199. return True
  200. else:
  201. logger.error("修复后仍无法启动服务")
  202. return False
  203. except Exception as e:
  204. logger.error(f"修复过程中发生错误: {str(e)}")
  205. return False
  206. def check_service_status():
  207. """检查服务状态并显示详细信息"""
  208. service_name = get_postgres_service_name()
  209. is_running = is_service_running(service_name)
  210. print(f"服务名称: {service_name}")
  211. print(f"运行状态: {'运行中' if is_running else '已停止'}")
  212. if is_running:
  213. try:
  214. # 尝试连接数据库验证服务状态
  215. import psycopg2
  216. try:
  217. conn = psycopg2.connect(
  218. dbname='postgres',
  219. user='postgres',
  220. password='abc@1234',
  221. host='localhost',
  222. port='5432'
  223. )
  224. conn.close()
  225. print("数据库连接: 正常")
  226. except Exception as e:
  227. print(f"数据库连接: 异常 ({str(e)})")
  228. except ImportError:
  229. print("数据库连接: 未安装 psycopg2 库,无法测试连接")
  230. return is_running
  231. def main():
  232. """主函数:提供命令行界面"""
  233. print("=" * 50)
  234. print("PostgreSQL 服务管理工具")
  235. print("=" * 50)
  236. while True:
  237. print("\n请选择操作:")
  238. print("1. 检查服务状态")
  239. print("2. 启动服务")
  240. print("3. 停止服务")
  241. print("4. 重启服务")
  242. print("5. 修复服务启动问题")
  243. print("6. 退出")
  244. choice = input("请输入选项 (1-6): ").strip()
  245. if choice == "1":
  246. print("\n检查服务状态...")
  247. check_service_status()
  248. elif choice == "2":
  249. print("\n启动服务...")
  250. if start_postgres_service():
  251. print("服务启动成功")
  252. else:
  253. print("服务启动失败,请尝试修复")
  254. elif choice == "3":
  255. print("\n停止服务...")
  256. if stop_postgres_service():
  257. print("服务停止成功")
  258. else:
  259. print("服务停止失败")
  260. elif choice == "4":
  261. print("\n重启服务...")
  262. if restart_postgres_service():
  263. print("服务重启成功")
  264. else:
  265. print("服务重启失败")
  266. elif choice == "5":
  267. print("\n修复服务启动问题...")
  268. if fix_postgres_service():
  269. print("服务修复成功")
  270. else:
  271. print("服务修复失败,请查看日志文件")
  272. elif choice == "6":
  273. print("退出程序")
  274. break
  275. else:
  276. print("无效选项,请重新选择")
  277. # input("\n按回车键继续...")
  278. if __name__ == "__main__":
  279. # 直接运行测试
  280. print("正在启动 PostgreSQL 服务管理工具...")
  281. main()