python_自动关闭&重启程序,备份数据

从配置文件读取参数,每周定时执行:停止程序,备份数据,重启程序。

# -*-coding: GBK -*-

import psutil
import os
import datetime
from apscheduler.schedulers.blocking import BlockingScheduler
import shutil
import time
import threading
import subprocess
import schedule
import asyncio

# 全局变量:配置文件
glob_config = "config_p.txt"


def txt_to_dict(filename):
    with open(filename, 'r', encoding='utf-8') as f:
        data_dict = {}
        for line in f:
            # 忽略空行和注释行
            if line.strip() == '' or line.startswith('#'):
                continue
            key, value = line.strip().split('=')
            data_dict[key] = value
    return data_dict


def txt_to_dict_l(filename):
    with open(filename, 'r', encoding='utf-8') as f:
        data_l = []
        for line in f:
            # 忽略空行和注释行
            if line.strip() == '' or line.startswith('#'):
                continue
            key, value = line.strip().split('=')
            if 'exe' in value:
                data_l.append(value)
    return data_l


def check_pid(process_path_pattern):
    # 获取所有运行中的进程
    all_processes = psutil.process_iter()
    # 存放pid
    pid_l = []
    # 遍历并打印每个进程的信息
    for proc in all_processes:
        if proc.name() == 'spe_post.exe':
            try:
                # 获取进程名称、PID和程序位置
                process_name = proc.name()
                process_id = proc.pid
                process_path = proc.exe()

                for ppp in process_path_pattern:
                    # 判断两个路径是否相等,匹配spe程序
                    if os.path.normcase(process_path) == os.path.normcase(ppp):
                        # 获取进程id
                        pid_l.append(process_id)
                        # 打印进程信息
                        # print(f"Process Name: {process_name}")
                        print(f"进程PID: {process_id}")
                        print(f"进程路径: {process_path}")
                        print("-----")
                    else:
                        print(f"*****运行中的该spe程序不在配置文件当中*****")

            except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                pass  # 忽略无法访问或已终止的进程
    # print(pid_l)
    return pid_l


def kill_process_by_pid(pid):
    try:
        # 获取进程对象
        process = psutil.Process(pid=pid)
        # 终止进程
        process.kill()
        print(f"*****进程PID: {pid} 已经被终止运行*****")
    except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
        pass  # 忽略无法访问或已终止的进程


def stop_process():
    # 读取配置文件,获取spe程序的绝对路径
    process_path_pattern = txt_to_dict_l(glob_config)

    # 获取运行中的spe程序pid
    pid_l = check_pid(process_path_pattern)

    if pid_l:
        for pid in pid_l:
            # 调用函数结束进程
            kill_process_by_pid(pid)
    else:
        print(f"*****当前无匹配的spe程序运行*****")

    # 等待10秒
    time.sleep(10)
    current_time = datetime.datetime.now()
    print(f"*****当前时间:{current_time},终止spe程序,执行完毕*****")
    # return "停止spe程序,执行完毕"


def move_file():
    # 读取配置文件,获取spe程序的绝对路径
    process_path_pattern = txt_to_dict_l(glob_config)

    # spe程序下需要移动的5个文件
    move_file = ['data.ssr', 'move.pos', 'move.raw', 'nav.raw', 'out_los.txt']

    # 读取配置文件,加载字典
    data = txt_to_dict(glob_config)
    # 获取特定键值对的值,指定父目录的名称
    parent_dir = data.get('parent_dir', 'null')
    # 指定子目录的名称
    now = datetime.datetime.now()
    child_dir = str(now.strftime('%Y%m%d-%H%M%S'))
    # 拼接子目录的完整路径
    child_dir_path = os.path.join(parent_dir, child_dir)
    # 创建子目录
    os.makedirs(child_dir_path, exist_ok=True)

    # 获取spe程序的上层目录
    for path_dir in process_path_pattern:
        # 获取文件的文件夹路径
        src_path = os.path.dirname(path_dir)

        # 重命名备份的文件夹名称
        if "PROD_V2_N" in src_path:
            print("*****PROD_V2_N环境的SSR文件*****")
            cchild_dir = "PROD_V2_N"
        elif "PROD_V2" in src_path:
            print("*****PROD_V2环境的SSR文件*****")
            cchild_dir = "PROD_V2"
        elif "PROD" in src_path:
            print("*****PROD环境的SSR文件*****")
            cchild_dir = "PROD"
        elif "TEST_V2_P" in src_path:
            print("*****TEST_V2_P环境的SSR文件*****")
            cchild_dir = "TEST_V2_P"
        elif "TEST_V2" in src_path:
            print("*****TEST_V2环境的SSR文件*****")
            cchild_dir = "TEST_V2"
        elif "TEST" in src_path:
            print("*****TEST环境的SSR文件*****")
            cchild_dir = "TEST"
        else:
            print("*****非PROD和TEST环境的SSR文件*****")
            cchild_dir = "NN"

        # 拼接子子目录的完整路径
        cchild_dir_path = os.path.join(child_dir_path, cchild_dir)
        # 创建子子目录
        os.makedirs(cchild_dir_path, exist_ok=True)

        for file in move_file:
            # 获取文件的完整路径
            src_file_path = os.path.join(src_path, file)
            # 获取目标路径
            dst_file_path = os.path.join(cchild_dir_path, file)
            # 判断文件是否存在
            if os.path.exists(src_file_path):
                # 移动文件
                shutil.move(src_file_path, dst_file_path)
                # print(f"移动文件完成:", dst_file_path)
                time.sleep(5)

    # 等待10秒
    time.sleep(10)
    current_time = datetime.datetime.now()
    print(f"*****当前时间:{current_time},移动文件,执行完毕*****")
    # return "移动文件,执行完毕"


def restart_process():
    # 读取配置文件,获取spe程序的绝对路径
    process_path_pattern = txt_to_dict_l(glob_config)

    # 执行可执行程序
    for executable_path in process_path_pattern:
        # 获取spe程序的文件夹路径
        exe_path = os.path.dirname(executable_path)
        # 先切换到spe程序的所在目录,再执行start启动命令
        cmd1 = 'cd' + ' ' + exe_path
        cmd2 = 'start spe_post.exe'
        os.system('%s && %s' % (cmd1, cmd2))
        # subprocess.run([executable_path])

    # 等待10秒
    time.sleep(10)
    current_time = datetime.datetime.now()
    print(f"*****当前时间:{current_time},重启spe程序,执行完毕*****")


def run_threading():
    # 创建线程并启动停止spe程序、移动文件、重启spe程序
    job_stop_process = threading.Thread(target=stop_process)
    job_move_file = threading.Thread(target=move_file)
    job_restart_process = threading.Thread(target=restart_process)

    # 启动线程,等待停止spe程序执行完成后,再移动文件,最后重启spe程序
    job_stop_process.start()
    job_stop_process.join()
    job_move_file.start()
    job_move_file.join()
    job_restart_process.start()
    job_restart_process.join()


# async def main():
#     # 等待程序1执行完成后再执行程序2
#     result1 = await stop_process()
#     result2 = await move_file()
#     print(result1)
#     print(result2)
#
# # 运行主程序
# asyncio.run(main())


if __name__ == '__main__':
    # 读取配置文件,加载字典
    data = txt_to_dict(glob_config)
    # 获取运行时间
    run_time_daily = data.get('run_time_daily', '08:10')
    run_time_weekly = data.get('run_time_weekly', 'mon')
    # 拆分运行时间为小时和分钟
    rt = run_time_daily.strip().split(':')
    ht, mt = int(rt[0]), int(rt[1])

    current_time = datetime.datetime.now()
    print(f"*****当前时间:{current_time},开始执行任务*****")

    # 创建调度器
    scheduler_weekly = BlockingScheduler()

    # 添加定时任务,使用cron表达式,表示每周的(mon,tue,wed,thu,fri,stat,sun)的ht:mt时刻执行一次
    # scheduler_weekly.add_job(run_threading, 'cron', week='*', day_of_week=run_time_weekly, hour=ht, minute=mt, second=0)

    # 添加定时任务,使用interval表达式,表示每间隔5秒执行一次
    # scheduler_weekly.add_job(run_threading, 'interval', seconds=5)

    # 添加定时任务,使用interval表达式,表示每间隔5分钟执行一次
    scheduler_weekly.add_job(run_threading, 'interval', minutes=60)

    # 开始调度器
    scheduler_weekly.start()

config文件如下:

# 每周执行任务(停止spe程序&备份数据&重启spe程序)-北京时间
# 小时&分钟
run_time_daily=15:01
# 可选mon,tue,wed,thu,fri,stat,sun分别表示星期一、二、三、四、五、六、日
run_time_weekly=thu


# spe程序的路径,默认test、test_p、prod、prod_n四个环境,若停止监控该环境,只需将该值置空或注释掉
#origin_path_test=E:/python/pythonProject1/threading_test/N_TEST_20231105.pos
origin_path_test=E:/data/PROD/sppost.exe
origin_path_test_p=E:/DPI/路测/0925版本SPE/sppost.exe
#origin_path_prod=E:/python/pythonProject1/threading_test/N_PROD_20231105.pos
#origin_path_prod_n=E:/python/pythonProject1/threading_test/N_PROD_20231105.pos


# 备份文件的路径
parent_dir=E:/data/备份

你可能感兴趣的:(python,数据结构,开发语言)