ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

pd2bs-scripts实战:打造全自动设备老化测试与报告生成

pd2bs-scripts实战:打造全自动设备老化测试与报告生成 简介这是一套面向暗黑破坏神2模组PD2玩家的自动化脚本集基于Kolbot框架构建能够实现自动建房、角色移动、技能释放、物品拾取等常用功能适合有一定脚本基础并希望深度定制机器人行为的玩家使用。压缩包共包含229个文件整体体积约707KB其中大部分为脚本文件151个其余为配置说明、拾取规则、任务入口文件等各文件用途清晰方便按需修改和扩展。已有 241 人浏览学习。脚本内提供了服务器配置项可通过修改获得更合适的游戏服务器同时包含技能编号查询和拾取规则说明帮助玩家自定义过滤逻辑针对程序崩溃问题也整理了更新版本、设置管理员权限等常见的修复办法。无论是优化联机路径、控制角色行为还是排查运行异常这套脚本都能为暗黑破坏神2的自动化游戏提供一套易于上手的扩展基础。 开头直接切入接触pd2bs也有一段时间了这工具在设备老化测试圈子里口碑一直不错但真正让它在团队里落地跑起来的还是配套的pd2bs-scripts脚本集。单纯用pd2bs裸跑也能做老化可一旦涉及批量设备、轮次切换、日志回传、异常重试这些真实工程需求没有一套脚本去编排人肉盯场能把你消耗到怀疑人生。这套脚本解决的核心问题就是把老化测试从“手动一条命令跑一轮”升级成“全自动多轮循环跑完还能自己出报告”。1. 项目背景与整体设计思路1.1 pd2bs到底在测什么pd2bs是一款面向硬件设备稳定性验证的命令行测试工具核心能力是给被测设备施加持续的压力负载在高强度运行状态下暴露潜在的可靠性缺陷。老化测试Burn-in Test本身就是个时间密集型工作一轮跑下来可能几小时甚至几天测试期间必须保证压力不间断、数据有记录、异常能感知。pd2bs本身的设计哲学是“单次任务只管执行”它不关心你今天要跑几轮、跑完要不要汇总、某个设备中途掉了要不要补测。这些工程化的编排逻辑恰恰是pd2bs-scripts存在的意义。1.2 为什么需要一套脚本而不是直接敲命令第一批用pd2bs的人多半是从手动敲命令开始的一轮一块设备命令敲完盯着终端等结果。设备少还行超过三块就开始乱了——每块设备一个终端窗口每轮结束要人工拷贝日志下轮开始再手动切配置一旦有几块设备掉线恢复后还得自己数轮次错一轮整批数据就废了。pd2bs-scripts的思路就是把这类重复劳动全部脚本化人工只负责“把设备接上、跑起来、回来看报告”。设计上遵循三个原则配置与代码分离测试参数写在独立配置文件里脚本不硬编码业务数据要调设备数量、循环轮次、压力时长改配置文件即可不用碰脚本本体。单设备故障不影响整批老化测试中单台设备掉线是常态脚本要能感知到掉线并把该设备剔除出本轮其他设备继续跑而不是整批罢工。日志和报告自动归档每台设备、每一轮、每一种压力的输出都按既定目录结构存放结束之后有一条命令汇总出报告不用手动翻找合并。这套设计直接决定了脚本集的目录组织方式和每个脚本的职责边界。2. 脚本集整体结构与核心模块拆解2.1 目录结构一眼看懂一个设计良好的脚本集拿到手先看目录就应该能猜出它是怎么工作的。pd2bs-scripts的目录划分就是围绕配置、执行、日志、报告四件事展开的pd2bs-scripts/ ├── config/ │ ├── devices.ini │ └── test_profile.json ├── scripts/ │ ├── precheck.sh │ ├── run_burnin.py │ ├── monitor.py │ └── report.py ├── logs/ │ └── (按日期批次自动生成) ├── reports/ │ └── (汇总报告输出目录) └── README.mdconfig目录放设备清单和测试档位scripts目录放四个核心脚本logs和reports是运行产物的落盘位置。这个结构看起来简单但实际用下来会发现把“配置”独立出来是老化测试脚本最关键的设计决策——因为老化测试的参数调整频率极高测一批新机型、换一种压力策略、调整循环次数都需要动参数如果参数埋在脚本逻辑里每次改动都要小心翼翼地找代码位置改错一个数整批测试报废。2.2 四个核心脚本各管一摊precheck.sh环境预检。检查pd2bs是否安装、版本是否符合要求、依赖库是否齐全、设备连接状态是否正常。它解决的是“跑到一半才发现环境不对”的尴尬。run_burnin.py主执行脚本。读取配置按设备逐台发起老化任务管理轮次循环处理设备掉线重试。monitor.py运行监控。定时探测各设备状态收集实时数据发现异常设备自动标记。report.py报告生成。汇总logs目录下的所有设备日志生成结果汇总表和异常列表。四个脚本通过文件系统解耦run_burnin.py只管执行和写日志monitor.py从日志和系统状态读取信息report.py最后汇总。这种松耦合设计的好处是某一块逻辑重写不会波及其他模块比如以后想换监控策略只动monitor.py就够了。3. 核心脚本实操与关键环节实现3.1 环境预检把问题拦截在开跑之前老化测试最怕的不是测试中出故障而是准备了两小时环境、设备全部接好了结果跑起来发现pd2bs版本不对或者某个依赖库缺失整个排期又得往后推。precheck.sh就是干这个的把前置校验全部自动化。脚本核心逻辑分三块。第一块检查pd2bs本身#!/bin/bash # scripts/precheck.sh # 检查pd2bs是否安装及版本兼容性 REQUIRED_VERSION2.4.0 INSTALLED_VERSION$(pd2bs --version 2/dev/null | grep -oP \d\.\d\.\d) if [ -z $INSTALLED_VERSION ]; then echo [ERROR] pd2bs 未安装或不在PATH中请先安装 pd2bs $REQUIRED_VERSION exit 1 fi # 将版本号按点号拆解为三段逐级比较确保主版本和次版本都满足要求 IFS. read -r MAJOR MINOR PATCH $INSTALLED_VERSION IFS. read -r REQ_MAJOR REQ_MINOR REQ_PATCH $REQUIRED_VERSION if [ $MAJOR -lt $REQ_MAJOR ] || \ { [ $MAJOR -eq $REQ_MAJOR ] [ $MINOR -lt $REQ_MINOR ]; }; then echo [ERROR] pd2bs 版本过低: 当前 $INSTALLED_VERSION, 需要 $REQUIRED_VERSION exit 1 fi echo [INFO] pd2bs 版本检查通过: $INSTALLED_VERSION版本比较这里有个细节直接用字符串比较在shell里会出问题因为2.10.0会被判为比2.4.0小所以必须把版本号拆开逐段比较。这块是我实际踩过坑的地方一开始图省事直接用字符串比结果某些设备上的pd2bs版本被误判为过低排查了半天才发现是比较逻辑的问题。第二块检查设备连接状态读取config/devices.ini中的设备ID列表逐个调用pd2bs的设备探测接口确认设备在线且可通信。第三块检查磁盘空间老化测试跑起来日志增长很快磁盘写满会直接导致测试中断所以预检脚本里预留了空间阈值判断默认低于5GB直接报警。3.2 主执行脚本轮次循环与异常容错run_burnin.py是整个脚本集的核心承担了最复杂的编排逻辑。它的工作流程是读取配置 → 建立设备列表 → 按循环次数发起老化任务 → 每轮结束后检查结果 → 设备掉线自动跳过 → 执行下一轮 → 全部结束后标记完成。代码骨架如下#!/usr/bin/env python3 # scripts/run_burnin.py pd2bs老化测试主执行脚本管理多设备多轮次的循环执行。 import json import logging import subprocess import sys import time from pathlib import Path def load_config(config_path: Path) - dict: 加载测试档位配置。 with open(config_path, r, encodingutf-8) as f: cfg json.load(f) # 配置合法性校验 assert devices in cfg and len(cfg[devices]) 0, 设备列表不能为空 assert cycles in cfg and cfg[cycles] 0, 循环次数必须大于0 assert stress_duration in cfg and cfg[stress_duration] 0, 压力时长必须大于0 return cfg def run_single_device(device_id: str, cfg: dict) - bool: 在指定设备上执行一轮老化测试返回是否成功。 cmd [ pd2bs, run, --device, device_id, --duration, str(cfg[stress_duration]), --profile, cfg[stress_profile], ] try: result subprocess.run(cmd, capture_outputTrue, textTrue, timeoutcfg.get(timeout, 3600)) if result.returncode ! 0: logging.error(f[{device_id}] pd2bs 执行失败: {result.stderr[-500:]}) return False return True except subprocess.TimeoutExpired: logging.error(f[{device_id}] 执行超时强制终止) return False except FileNotFoundError: logging.error(f[{device_id}] pd2bs 命令不存在请检查PATH) sys.exit(1) def main(): logging.basicConfig( levellogging.INFO, format%(asctime)s [%(levelname)s] %(message)s, handlers[ logging.FileHandler(logs/run_burnin.log, encodingutf-8), logging.StreamHandler(), ], ) cfg load_config(Path(config/test_profile.json)) devices cfg[devices] cycles cfg[cycles] # 统计字段记录每台设备的完成轮次、失败轮次和当前状态 stats {dev: {finished: 0, failed: 0, skipped: 0} for dev in devices} for cycle in range(1, cycles 1): logging.info(f 第 {cycle}/{cycles} 轮开始 ) alive_devices get_alive_devices(devices) # 每轮动态探测在线设备 for dev in alive_devices: if is_device_offline(dev): stats[dev][skipped] 1 logging.warning(f[{dev}] 本轮离线跳过) continue logging.info(f[{dev}] 开始老化测试 (第{cycle}轮)) success run_single_device(dev, cfg) if success: stats[dev][finished] 1 else: stats[dev][failed] 1 mark_cycle_done(dev, cycle) # 在日志中标记该设备该轮已完成 # 每轮结束后等待冷却时间避免设备过热影响下一轮表现 cooldown cfg.get(cooldown_seconds, 0) if cooldown 0 and cycle cycles: logging.info(f本轮结束冷却 {cooldown}s) time.sleep(cooldown) # 输出汇总统计 print(json.dumps(stats, ensure_asciiFalse, indent2)) logging.info(全部轮次执行完毕) if __name__ __main__: main()这里有一个关键点在get_alive_devices函数——每轮开始前动态探测一次设备在线状态而不是用开始时的固定列表。原因很简单老化测试期间设备可能因为过热重启、系统崩溃、接口松动等原因掉线如果脚本还坚持对掉线设备发起测试不仅浪费时间还会让测试结果完全不可信。动态探测之后掉线设备自动跳过等下一轮再探测如果恢复了就重新参与测试这在日常执行里非常实用。轮次之间的冷却时间也是经验值。不同设备对高温的容忍度不一样有些设备在八轮连续压力之后温度会明显异常但留出两三分钟的冷却让设备喘口气下一轮的稳定性会有肉眼可见的提升。冷却时长作为配置项暴露出来具体值需要结合设备规格和现场实测来定我给的建议参数是3到5分钟设备温度敏感型的话可以放宽到10分钟。3.3 监控脚本实时盯场异常早发现run_burnin.py是发起任务的主力但老化测试跑起来之后不能完全“跑完再看结果”尤其是多设备批量测试的时候某台设备可能第一轮就挂了结果没人发现后面几轮全是无效测试。monitor.py就承担了这个盯场的角色。它的实现思路是每隔一段时间去探测一次设备状态把在线状态、温度、本轮执行进度写入一个状态文件同时对比上一次探测结果如果设备从在线变成离线立刻发出告警。这个“状态变化检测”远比单纯的“设备是否在线”更有价值——一台设备从开始就一直离线和一台设备中途掉线处理优先级完全不同后者说明可能出现了真实故障。# scripts/monitor.py 核心逻辑片段 def check_device_health(device_id: str) - dict: 探测单台设备状态返回状态字典。 try: result subprocess.run( [pd2bs, status, --device, device_id], capture_outputTrue, textTrue, timeout10, ) if result.returncode ! 0: return {id: device_id, online: False, temp: None, running: False} temp parse_temperature(result.stdout) return {id: device_id, online: True, temp: temp, running: True} except subprocess.TimeoutExpired: return {id: device_id, online: False, temp: None, running: False}监控脚本还可以扩展一个功能设备温度过高时主动跳过下一轮任务。办法是让monitor.py写一个冷却标记文件run_burnin.py在每轮开始前读取这个标记如果发现某设备被标记为“当前过温”就临时跳过该设备。3.4 报告生成多设备多轮日志汇总老化测试结束后最痛苦的事情是什么是把几十个日志文件翻一遍人工确认哪些设备过了、哪些挂了、挂在哪一轮。report.py就是把这个手工活自动化了。脚本逻辑很简单遍历logs目录下按设备编号分组的所有日志检查每一轮是否有正常完成的标记最后生成一个CSV格式的汇总表包含设备ID、总轮次、完成轮次、失败轮次、首次失败轮次和状态结论。def generate_report(log_root: Path, output_path: Path) - None: rows [] for device_log_dir in sorted(log_root.iterdir()): if not device_log_dir.is_dir(): continue device_id device_log_dir.name total_cycles, finished, failed, first_failed analyze_device_log(device_log_dir) status PASS if failed 0 else FAIL rows.append({ device: device_id, total_cycles: total_cycles, finished: finished, failed: failed, first_failed_cycle: first_failed, status: status, }) write_csv(rows, output_path)汇总表一键生成看到FAIL的设备再单独去翻对应日志排查效率比人工翻日志高了一个数量级。4. 任务编排与自动化集成4.1 定时任务让老化测试无人值守脚本本身解决了“怎么跑”的问题但真正的无人值守还差一块拼图定时拉起。老化测试经常要安排在夜间执行白天设备还要做其他功能测试。这时候Linux环境用crontabWindows环境用计划任务把precheck.sh和run_burnin.py串成一条命令链。Linux下的定时任务配置示例# 每晚22:00执行预检预检通过后启动老化测试 0 22 * * * cd /opt/pd2bs-scripts ./scripts/precheck.sh python3 scripts/run_burnin.py logs/cron.log 21这里有个小技巧cd /opt/pd2bs-scripts不能省。crontab执行命令时的当前目录默认是用户主目录如果脚本内部用了相对路径访问config目录不先cd过去必然会报文件找不到。这个问题几乎每个用crontab跑脚本的人都踩过提前养成交作业系统里写绝对路径的习惯能省很多排查时间。Windows环境用任务计划程序操作路径是创建基本任务 → 触发器选每天22:00 → 操作选启动程序 → 程序填powershell.exe参数填-ExecutionPolicy Bypass -File C:\pd2bs-scripts\scripts\run_burnin.ps1。注意-ExecutionPolicy Bypass这个参数Windows PowerShell默认执行策略是Restricted跑未签名的脚本文件会被拦下来必须显式指定Bypass或RemoteSigned才能放行。这是热词列表中“无法加载文件因为禁止运行脚本”这类报错的标准解法后面排查章节还会详细说。4.2 与CI/CD流水线集成如果团队已经有了一套CI系统GitLab CI、Jenkins等都行pd2bs-scripts也可以作为流水线中的一个测试阶段来运行。这种方式的价值在于把老化测试纳入产品发布前的自动门禁任何一次代码合并或固件更新都自动触发一轮老化验证通过才允许继续发布流程。以GitLab CI为例在.gitlab-ci.yml中定义一个老化测试jobburnin_test: stage: test script: - bash scripts/precheck.sh - python3 scripts/run_burnin.py - python3 scripts/report.py artifacts: paths: - logs/ - reports/ expire_in: 7 days将logs和reports目录作为流水线产物保存这样每次跑完的测试结果都自动归档到CI系统后续追溯问题、对比不同版本的稳定性数据都直接从CI端下载不用再跑现场去拷日志。4.3 多设备并行调度的经验pd2bs本身支持单条命令指定一个设备但如果有多块设备要同时测脚本层面就要考虑并行度控制。直接for循环串行跑当然最简单但每轮耗时乘以设备数量总时间会非常长。翻经验来看合理的做法是用Python的ThreadPoolExecutor按设备维度并行发起pd2bs进程同时控制最大并发数——一般建议同时跑4到6台超过这个数字主机的CPU和IO会成为瓶颈反而拖慢整体效率。from concurrent.futures import ThreadPoolExecutor, as_completed with ThreadPoolExecutor(max_workerscfg.get(max_parallel, 4)) as executor: future_map { executor.submit(run_single_device, dev, cfg): dev for dev in alive_devices } for future in as_completed(future_map): dev future_map[future] try: success future.result() stats[dev][finished if success else failed] 1 except Exception as e: logging.error(f[{dev}] 执行异常: {e}) stats[dev][failed] 1线程数量不是越大越好这算是并行调度中最容易栽的坑。我自己试过把并发拉到8结果设备侧倒是没问题主机的CPU使用率飙到90%以上反而导致部分pd2bs进程响应变慢个别设备出现了不明原因的执行超时。后来压回4并发一切都正常了。这个经验具体数值可能因主机配置而异但思路是通用的调并发数要用压测的眼光去测看效果曲线找拐点而不是想当然地给个很大的数。5. 常见问题与排查技巧实录5.1 PowerShell禁止运行脚本很多用Windows做自动化的人第一次跑.ps1脚本都会撞见那句魔性的报错“无法加载文件 xxx.ps1因为在此系统上禁止运行脚本。有关详细信息请参阅 https:/go.microsoft.com/fwlink/?LinkID135170 中的 about_Execution_Policies。”原因就是PowerShell的默认执行策略是Restricted所有.ps1脚本都被视为不可信。解决办法有两种。一种是一劳永逸地把当前用户的执行策略改成RemoteSignedSet-ExecutionPolicy -Scope CurrentUser RemoteSignedRemoteSigned意味着本地创建的脚本可以运行从网络上下载的脚本必须带数字签名才能运行安全性和便利性兼顾是最推荐的选项。另一种是只在执行单条命令时临时放行不修改系统策略powershell.exe -ExecutionPolicy Bypass -File .\scripts\run_burnin.ps1这种方式适合偶尔跑一次、不想动系统设置的场景。需要注意的坑是Set-ExecutionPolicy改的是注册表里的持久配置有些团队机器上有组策略锁定了这项设置本地执行时会报“拒绝访问”那种情况只能用-ExecutionPolicy Bypass方式绕过去。5.2 找不到命令/脚本文件不存在热词列表中频繁出现的“claude、git、opencode、pnpm、mvn无法识别”本质上是一个问题命令所在的目录不在系统PATH环境变量中。常见于新装的软件、或者是用Node.js包管理器安装的CLI工具安装路径没有被自动加入PATH。排查思路分三步。第一步确认软件到底装没装Windows下看安装目录是否存在Linux下用which或whereis找一下which pd2bs whereis pd2bs如果命令存在但不在PATH里输出会显示完整路径。第二步确认输出路径是否在PATH环境变量里echo $PATHWindows PowerShell则用$env:Path -split ;第三步把缺少的路径加进PATH。Linux临时生效是export PATH$PATH:/opt/pd2bs/bin永久写入~/.bashrc或/etc/profile.d/xxx.sh。Windows在系统设置里编辑环境变量界面添加路径即可但要注意添加后必须重新打开终端窗口才生效已经打开的老窗口不会自动刷新环境变量这一点经常让人误以为没改成功。5.3 设备掉线导致测试中断用pd2bs跑长时间老化时最常见的失败模式是设备在深夜掉线然后整批测试卡住或者退出。排查掉线原因要分物理层和系统层。物理层先看连接线接口是否松动老化测试期间设备有震动连接线很容易松脱系统层要看设备是否因为过热或驱动异常导致系统挂死。脚本侧的建议是两层防护。第一层是run_burnin.py里每轮开始前的动态设备探测掉线就跳过不阻塞整批第二层是monitor.py持续记录设备状态变化掉线时间点、恢复时间点都有据可查事后分析原因定位问题非常有用。很多团队的设备掉线问题长期说不清楚就是因为没有这种连续的状态监控记录。5.4 日志占用空间过大老化测试动辄数十轮每轮每台设备都会产生几百MB日志logs目录的膨胀速度快得惊人。磁盘满时pd2bs会直接写不进日志进程崩溃。建议在precheck.sh里加一个磁盘空间检查低于阈值时直接拒绝启动测试。另一个实用做法是定期清理历史日志保留最近两个批次的完整日志更早的打包压缩后转存到文件服务器。这个策略可以用一个简单的crontab任务实现# 每天凌晨4点清理7天前的日志保留压缩包 30 4 * * * find /opt/pd2bs-scripts/logs -name *.log -mtime 7 -exec gzip {} \;压缩后的日志直接改成.gz后缀report.py读取时做一个透明解压处理就行。老化测试日志一般是文本密集型gzip压缩率通常在80%以上一个1GB的日志压完不到200MB对存储的友好程度不言而喻。6. 老测试工程师的几点体会用pd2bs-scripts跑了小半年最深的感受是老化测试的自动化并不难真正难的是把各种边界情况纳入考虑。刚开始只写了run_burnin.py一个脚本跑起来发现设备掉线没人管、日志多了磁盘爆掉、定时任务里相对路径找不到文件一个个问题往外冒才逐步补上了precheck、monitor、report这几个配套模块。现在回头看四个脚本各司其职缺一个都有明显的痛点。一个小技巧作为收尾分享在配置里加一个batch_name字段每批测试手动指定一个批次名比如20260610_batch1日志和报告的归档路径自动带上这个批次名。别小看这个细节当测试跨月积累、需要回溯某批设备的数据时批次名比时间戳好用得多——时间戳只能告诉你什么时候跑的批次名还能传达这一批是谁在什么场景下安排的追溯效率完全不是一个级别。本文还有配套的精品资源点击获取
返回列表