Skip to content

Commit 6b94fd2

Browse files
committed
feat: 新增内存检测倒计时关服通知
1 parent 7607e33 commit 6b94fd2

File tree

1 file changed

+65
-46
lines changed

1 file changed

+65
-46
lines changed

Diff for: task_scheduler.py

+65-46
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,14 @@ def __init__(self):
2424
self.daemon_time = self.conf['daemon_time']
2525
self.arguments = self.conf.get('arguments', '').split()
2626
self.is_first_run = True
27+
self.is_restarting = False
2728

2829
# 修改rcon源代码,忽略SessionTimeout异常
2930
def patched_run(self, command: str, *args: str, encoding: str = "utf-8") -> str:
3031
"""Patched run method that ignores SessionTimeout exceptions."""
3132
request = Packet.make_command(command, *args, encoding=encoding)
3233
response = self.communicate(request)
3334

34-
# Ignore SessionTimeout exceptions
35-
# if response.id != request.id:
36-
# raise SessionTimeout()
37-
3835
return response.payload.decode(encoding)
3936

4037
# Apply the monkey patch
@@ -56,7 +53,10 @@ def check_rcon(self):
5653
except TimeoutError:
5754
INFO.logger.error("[ RCON ] 正在检测RCON连接,请不要关闭......")
5855
print("[ RCON ] 正在检测RCON连接,请不要关闭......")
59-
return False
56+
if self.is_first_run:
57+
time.sleep(1)
58+
else:
59+
return False
6060
except rcon.exceptions.WrongPassword:
6161
INFO.logger.error("[ RCON ] RCON密码错误,请检查相关设置")
6262
print("[ RCON ] RCON密码错误,请检查相关设置")
@@ -93,7 +93,7 @@ def start_program(self):
9393
while time.time() - start_time < 60:
9494
if self.check_rcon():
9595
break
96-
time.sleep(1) # 每次尝试后,暂停1秒
96+
time.sleep(1)
9797

9898
else:
9999
INFO.logger.error("[ RCON ] 无法在60秒内建立RCON连接")
@@ -126,59 +126,54 @@ def polling_task(self):
126126
INFO.logger.info(f'[ 轮询任务 ] 服务器将进入重启倒计时,设置时长为 {self.conf["restart_interval"]} 秒......')
127127
print(f'\r[ 轮询任务 ] 服务器将进入重启倒计时,设置时长为 {self.conf["restart_interval"]} 秒......')
128128

129-
# 如果设置了检查内存使用情况memory_monitor_enabled
130-
if self.conf['memory_monitor_enabled']:
131-
time.sleep(1)
132-
INFO.logger.info(f"[ 内存监控 ] 已开启内存监控,每{self.conf['polling_interval_seconds']}秒检查一次,将在内存使用超过{self.conf['memory_usage_threshold']}%时重启程序")
133-
print(f"\r[ 内存监控 ] 已开启内存监控,每{self.conf['polling_interval_seconds']}秒检查一次,将在内存使用超过{self.conf['memory_usage_threshold']}%时重启程序")
134-
135129
# 服务器持续运行时间(重启间隔)
136130
for i in range(int(self.conf['restart_interval']), 0, -1):
131+
print("\r\033[K", end='') # 清除当前行
132+
print(f'\r[ 轮询任务 ] 服务器将在 {i} 秒后重启......', end='')
133+
time.sleep(1)
134+
# 检查内存使用情况
137135
if self.conf['memory_monitor_enabled']:
138136
if self.conf['polling_interval_seconds'] > 5:
139-
# 检查内存使用情况
140137
mem_info = psutil.virtual_memory()
141138
mem_usage = mem_info.percent # 获取内存使用百分比
142-
# 如果内存使用超过阈值,则跳出倒计时,进行重启操作
139+
140+
# 内存超限关服消息提醒
143141
if mem_usage > self.conf['memory_usage_threshold']:
142+
self.is_restarting = True # 开始重启
143+
max_notice_time = max(map(int, self.conf['shutdown_notices'].keys())) # 获取最大关服通知时间
144144
INFO.logger.error(f"[ 内存监控 ] 内存使用超过{self.conf['memory_usage_threshold']}%,正在重启程序......")
145-
print(f"[ 内存监控 ] 内存使用超过{self.conf['memory_usage_threshold']}%,正在重启程序......")
146-
break
145+
print(f"\r[ 内存监控 ] 内存使用超过{self.conf['memory_usage_threshold']}%,正在重启程序......")
146+
time.sleep(1)
147+
# 倒计时关闭服务端
148+
for j in range(max_notice_time, 0, -1):
149+
time.sleep(1)
150+
self.send_shutdown_notice(j)
151+
subprocess.run(['taskkill', '/f', '/im', self.appName], stderr=subprocess.DEVNULL)
152+
self.is_first_run = True
153+
time.sleep(5)
154+
self.start_program()
155+
self.is_restarting = False # 重启完成
156+
147157
else:
148158
INFO.logger.error("[ 内存监控 ] 轮询间隔 polling_interval_seconds 必须大于等于5秒,请重新设置!")
149159
print("[ 内存监控 ] 轮询间隔 polling_interval_seconds 必须大于5秒,请重新设置!")
150160
time.sleep(2)
151161
exit(0)
152162

153-
# 还剩30秒的时候发送rcon关服消息提醒
163+
# 还剩 x 秒的时候发送rcon关服消息提醒
154164
if str(i) in self.conf['shutdown_notices'] and self.conf['rcon_enabled']: # 检查是否有对应的通知
155165
if self.conf['rcon_command']:
156-
INFO.logger.info("RCON指令 {0},正在发送通知......".format(self.conf['rcon_command']))
157-
print("\r\033[K", end='')
158-
print("RCON指令 {0},正在发送通知......".format(self.conf['rcon_command']))
159-
try:
160-
with Client(
161-
host=self.conf['rcon_host'],
162-
port=self.conf['rcon_port'],
163-
passwd=self.conf['rcon_password'],
164-
timeout=1) as client:
165-
message = self.conf['shutdown_notices'][str(i)]
166-
response = client.run(f"{self.conf['rcon_command']} {message}", 'utf-8')
167-
INFO.logger.info('[指令发送] {0}'.format(response))
168-
print('[指令发送] ', response)
169-
except TimeoutError:
170-
INFO.logger.error("RCON连接超时,请检查IP和端口是否填写正确")
171-
print("\r\033[K", end='')
172-
print("RCON连接超时,请检查IP和端口是否填写正确")
173-
except rcon.exceptions.WrongPassword:
174-
INFO.logger.error("RCON密码错误,请检查相关设置")
175-
print("\r\033[K", end='')
176-
print("RCON密码错误,请检查相关设置")
177-
178-
print(f'\r[ 轮询任务 ] 服务器将在 {i} 秒后重启......', end='')
179-
time.sleep(1)
180-
181-
# 关闭服务端 放在循环的结尾,可以让用户不用关闭服务器的情况下启动本脚本
166+
with Client(
167+
host=self.conf['rcon_host'],
168+
port=self.conf['rcon_port'],
169+
passwd=self.conf['rcon_password'],
170+
timeout=1) as client:
171+
message = self.conf['shutdown_notices'][str(i)]
172+
response = client.run(f"{self.conf['rcon_command']} {message}", 'utf-8')
173+
INFO.logger.info('[指令发送] {0}'.format(response))
174+
print('\r[指令发送]', response)
175+
176+
# 关闭服务端
182177
INFO.logger.info("[ 轮询任务 ] 正在关闭任何在运行的 PalServer 服务......")
183178
print("\r\033[K", end='')
184179
print("[ 轮询任务 ] 正在关闭任何在运行的 PalServer 服务......")
@@ -193,7 +188,7 @@ def start_daemon(self):
193188
try:
194189
result = subprocess.run(['tasklist', '/FI', 'IMAGENAME eq PalServer.exe'], capture_output=True,
195190
text=True)
196-
if 'PalServer.exe' not in result.stdout:
191+
if 'PalServer.exe' not in result.stdout and (not self.is_restarting):
197192
print("\r\033[K", end='')
198193
print('[ 守护进程 ] 监控到 PalServer 已停止,正在重新启动......')
199194

@@ -211,6 +206,21 @@ def start_daemon(self):
211206
print(f"[ 守护进程 ] 程序异常终止,错误信息:{e}\n正在尝试重启程序......")
212207
continue
213208

209+
def send_shutdown_notice(self, countdown):
210+
"""Send a shutdown notice through RCON."""
211+
if self.conf['rcon_enabled']: # 检查是否开启通知
212+
if str(countdown) in self.conf['shutdown_notices']:
213+
if self.conf['rcon_command']:
214+
with Client(
215+
host=self.conf['rcon_host'],
216+
port=self.conf['rcon_port'],
217+
passwd=self.conf['rcon_password'],
218+
timeout=1) as client:
219+
message = self.conf['shutdown_notices'][str(countdown)]
220+
response = client.run(f"{self.conf['rcon_command']} {message}", 'utf-8')
221+
INFO.logger.info('[指令发送] {0}'.format(response))
222+
print('\r[指令发送]', response)
223+
214224

215225
def main():
216226
Task = TaskScheduler()
@@ -220,15 +230,24 @@ def main():
220230
print("[ 轮询任务 ] 已启动,每隔{0}秒重启 PalServer 进程......".format(Task.conf['restart_interval']))
221231
polling_thread.start()
222232
time.sleep(1)
233+
223234
# [ 轮询任务 ] 必须在最初启动 防止[ 轮询任务 ] kill掉[ 守护进程 ] 刚启动的服务端
224235
if Task.conf['daemon_enabled']:
225236
print("\r\033[K", end='')
226-
INFO.logger.info("[ 守护进程 ] 守护进程已开启,延迟5秒启动避免双端开启,每隔{0}秒检查一次......".format(Task.conf['daemon_time']))
227-
print("[ 守护进程 ] 守护进程已开启,延迟5秒启动避免双端开启,每隔{0}秒检查一次......".format(Task.conf['daemon_time']))
237+
INFO.logger.info("[ 守护进程 ] 守护进程已开启,延迟5秒启动避免双端开启,每隔{0}秒检查一次......".format(
238+
Task.conf['daemon_time']))
239+
print("[ 守护进程 ] 守护进程已开启,延迟5秒启动避免双端开启,每隔{0}秒检查一次......".format(
240+
Task.conf['daemon_time']))
228241
time.sleep(5) # 再延迟5秒 避免脚本启动时双开服务端。尽量避免10结尾以免和[ 轮询任务 ] 倒计时同时结束
229242
daemon_thread = threading.Thread(target=Task.start_daemon)
230243
daemon_thread.start()
231244

245+
if Task.conf['memory_monitor_enabled']:
246+
INFO.logger.info("[ 内存监控 ] 已开启内存监控,每{0}秒检查一次,将在内存使用超过{1}%时重启程序".format(
247+
Task.conf['polling_interval_seconds'], Task.conf['memory_usage_threshold']))
248+
print("[ 内存监控 ] 已开启内存监控,每{0}秒检查一次,将在内存使用超过{1}%时重启程序".format(
249+
Task.conf['polling_interval_seconds'], Task.conf['memory_usage_threshold']))
250+
232251
polling_thread.join()
233252
if Task.conf['daemon_enabled']:
234253
daemon_thread.join()

0 commit comments

Comments
 (0)