from datetime import datetime import servicemanager import win32event import win32service import win32serviceutil import threading from Common import * current_dir = os.path.dirname(sys.executable) if getattr(sys, 'frozen', False) else os.path.dirname( os.path.abspath(__file__)) service_name = "ComacDatabase" service_description = "Comac数据库组件服务" java_exe = os.path.join(current_dir, "jdk", "bin", "java.exe") jar_path = os.path.join(current_dir, "electromagnetic.jar") app_log_dir = os.path.join(current_dir, "logs") class ComacDBService(win32serviceutil.ServiceFramework): _svc_name_ = service_name # 服务名称 _svc_display_name_ = service_name # 显示名称 _svc_description_ = service_description # 服务描述 def __init__(self, args): win32serviceutil.ServiceFramework.__init__(self, args) self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) self.process = None self.service_ready = False def SvcDoRun(self): try: # 报告服务正在启动 self.ReportServiceStatus(win32service.SERVICE_START_PENDING, waitHint=10000) formatted_time = datetime.now().strftime("%Y%m%d%H%M%S") cmd = [ java_exe, f"-jar", jar_path, f"--file.enc.passwd=adknfhkj87654knd", f"--logging.file.path={app_log_dir}", f"--logging.file.name={app_log_dir}/app_{formatted_time}.log", f"--winPrefix={current_dir}", f"--spring.datasource.username={mariadb_user}", f"--spring.datasource.password={mariadb_passowrd}", f"--server.port={comac_db_port}", f"--spring.datasource.url=jdbc:mariadb://127.0.0.1:{mariadb_port}/{mariadb_init_schema}?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&sslModel=true&serverTimezone=GMT%2B8&allowMultiQueries=true&rewriteBatchedStatements=true" ] # 添加完整的错误处理 env = os.environ.copy() startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW startupinfo.wShowWindow = 0 # 隐藏窗口 # 启动Java进程(使用subprocess.Popen捕获输出) try: self.process = subprocess.Popen( cmd, cwd=app_log_dir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW, env=env, startupinfo=startupinfo ) logger.info(f"Java process started with PID: {self.process.pid}") # 检查进程是否存活 time.sleep(2) # 给Java启动时间 if self.process.poll() is not None: # 读取输出以诊断问题 output, _ = self.process.communicate(timeout=2) output = output.decode('gbk', errors='ignore') logger.error(f"Java process exited prematurely. Output: {output}") self.ReportServiceStatus(win32service.SERVICE_STOPPED) return except Exception as e: logger.error(f"Failed to start Java process: {str(e)}") self.ReportServiceStatus(win32service.SERVICE_STOPPED) return # 服务完全启动 self.ReportServiceStatus(win32service.SERVICE_RUNNING) self.service_ready = True logger.info("Service fully started and running") # 启动线程监控Java进程 self.monitor_java_process() # 等待停止信号 win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE) except Exception as e: logger.error(f"Service failed: {str(e)}", exc_info=True) self.ReportServiceStatus(win32service.SERVICE_STOPPED) finally: # 确保清理资源 if self.process and self.process.poll() is None: self.process.terminate() self.process = None def monitor_java_process(self): """在后台线程中监控Java进程""" def monitor(): try: if self.process: # 持续读取输出 while self.process.poll() is None and self.service_ready: line = self.process.stdout.readline() if line: line = line.decode('gbk', errors='ignore').strip() logger.info(f"JAVA: {line}") else: time.sleep(0.5) # 检查进程退出原因 if self.process.poll() is not None: logger.warning(f"Java process exited with code: {self.process.poll()}") except Exception as e: logger.error(f"Monitor thread error: {str(e)}") # 启动监控线程 threading.Thread(target=monitor, daemon=True).start() def SvcStop(self): # 报告服务正在停止 self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) # 停止Java进程(如果存在) if self.process: try: # 更优雅的关闭方式 logger.info("Terminating Java process...") self.process.terminate() # 等待最多10秒 for _ in range(10): if self.process.poll() is not None: break time.sleep(1) else: logger.warning("Java process did not exit, using force kill") self.process.kill() except Exception as e: logger.error(f"Error stopping Java process: {str(e)}") # 通知主线程停止 win32event.SetEvent(self.hWaitStop) self.service_ready = False # 报告服务已停止 self.ReportServiceStatus(win32service.SERVICE_STOPPED) logger.info("Service stopped successfully") pass if __name__ == '__main__': ensure_dir(app_log_dir) logger.add( sink=os.path.join(app_log_dir, "ManagerService.log"), rotation="10 MB", retention="1 days", compression="zip", enqueue=True, format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}" ) if len(sys.argv) == 1: servicemanager.Initialize() servicemanager.PrepareToHostSingle(ComacDBService) servicemanager.StartServiceCtrlDispatcher() else: # 处理 install/update/remove 等命令 win32serviceutil.HandleCommandLine(ComacDBService) if "install" in sys.argv: win32serviceutil.ChangeServiceConfig( pythonClassString=win32serviceutil.GetServiceClassString(ComacDBService), serviceName=service_name, startType=win32service.SERVICE_AUTO_START, )