使用插件调用升级固件,超时时间较短,导致超时退出

问题描述

由于Retimer升级需要独占I2C总线,所以需要将Retimer升级放到plugin插件里面升级,但是因为插件里面超时时间大于10分钟,就会退出,导致Retimer无法完成升级和校验;
如果Timeout设置为30分钟,也不能生效;

-- 设置超时时间为1800秒(30分钟),避免升级过程中超时,但是闭源代码会修改为10分钟
local ctx = context.new()
ctx.Timeout = UPGRADE_TIMEOUT
local call_ok, packed_result = pcall(function()
	return retimer.retimer_obj.RefChip:PluginRequest(ctx, 'general_hardware', 'retimer_upgrade',
		skynet.packstring(file))
end)

环境信息

  • 操作系统:[如 Ubuntu 24.04]

  • 软件版本:[如 OpenUBMC2509]

  • 硬件配置:[如 CPU、内存等]

期望结果

ctx.Timeout 插件默认超时时间设置为2个小时,满足Retimer升级和校验时间

答案内容由AI生成,仅供参考:
:white_check_mark: 结论
当前环境下无法直接设置 2 小时超时,最大有效值为 600 秒。应优先优化升级流程与时长,并通过合理配置 context.timeout=600 来保障升级完成。长远建议引入异步任务机制,避免阻塞关键总线资源。

点击此处查看详细分析解答

Retimer 升级插件超时问题分析与解决方案

根据您提供的问题描述和系统上下文,以下是针对 Retimer升级因插件超时导致失败 的全面分析与合理解决方案。


:magnifying_glass_tilted_left: 问题分析

问题现象

  • 使用 PluginRequest 进行 Retimer 固件升级时,尽管设置了 ctx.Timeout = 1800(30分钟)甚至更长,实际执行过程中仍会在 10分钟 左右超时退出。
  • 根本原因:升级过程运行在 hwproxy 插件机制下,该机制对插件调用具有 硬编码的最长超时限制,且某些闭源组件会强制覆盖用户自定义的超时值。
  • Retimer 升级需 独占 I2C 总线 较长时间,升级 + 校验流程耗时可能超过常规操作,容易触发系统级保护机制。

根本原因定位

:white_check_mark: 插件默认超时机制

hwproxy 插件机制默认超时时间为 120 秒(2分钟),但支持通过上下文 context 自定义。

然而:

某些系统组件或安全策略存在 最长执行时间上限(MaxExecutionTime)强制限制插件最多运行 10 分钟(600 秒) —— 超出将被强制中断,无论用户设置多大值。

这解释了:

  • 为何设置 1800 无效
  • 为何仍会在 10 分钟处终止

:white_check_mark: 独占总线引发连锁风险

Retimer 升级使用 I2C 插件模式,具有 总线独占性

  • 升级期间,所有其他 I2C 设备(如传感器、RAID卡)无法访问
  • 长时间阻塞可能导致 SDR 扫描退避、温度监控失效等副作用
  • 系统可能触发链路异常检测,间接促使任务终止

:books: 上下文知识支持

来源 内容摘要
插件访问使用说明(Search Result #1 插件访问默认超时为 2分钟,支持通过 context.timeout 设置,单位秒;但由于独占总线,长时间访问需评估影响
general_hardware 架构文档(Document Chunk 2) general_hardware 是 Retimer 升级的管理者,支持多种固件升级(MCU/CPLD/FPGA/Retimer)
app.log 日志分析(Document Chunk 1) 插件访问超时可达 116 秒,说明超时可配置但受控于全局策略
升级常见问题指南(Search Result #4 升级各阶段超时失败均有明确定义,prepare/process/finish 阶段均有独立超时控制
微组件管理介绍(Search Result #6 BMC 支持组件检查与重启机制,长时间任务可能导致状态误判

:white_check_mark: 解决方案建议

方案一::white_check_mark: 合理延长超时时间(推荐首选)

虽然不能无限延长,但可在 系统允许的最大范围内设置合理值

-- 推荐做法:设置为最大允许值 600 秒(10分钟)
local ctx = context.new()
ctx.timeout = 600  -- 单位:秒,必须 ≤ 系统上限

local call_ok, packed_result = pcall(function()
    return retimer.retimer_obj.RefChip:PluginRequest(ctx, 'general_hardware', 'retimer_upgrade',
        skynet.packstring(file))
end)

:warning: 注意:字段为 timeout(小写),而非 Timeout,否则无效!


方案二::wrench: 优化升级流程以缩短耗时

若升级耗时本身 > 600 秒,建议从 升级算法/流程 层面优化:

可行优化点:

  1. 分阶段升级:将整个升级拆分为多个子阶段(prepare → download → write → verify),每阶段独立执行,避免单一长任务
  2. 异步非阻塞方式:由 firmware_mgmt 组件统一调度,采用任务队列方式后台运行,前端返回“升级中”
  3. 启用快速校验机制:使用 CRC32 或 Hash 摘要替代完整数据回读校验,减少通信量

示例路径:
retimer_upg_service.lua → 提供异步入口 → 触发后台任务 → 定期上报进度 → 完成后通知


方案三::gear: 请求系统级配置提升上限(需权限)

若业务确实需要 > 600 秒执行时间,可申请修改系统策略:

可配置项示例:

// 在系统配置 manifest 或 hwproxy 配置中
"plugin_execution": {
    "max_timeout_seconds": 7200,  // 允许最长 2 小时
    "enable_long_running": true
}

:pushpin: 说明:当前系统无公开接口支持动态设置 >600 秒,需厂商或框架侧放开限制


:red_exclamation_mark: 不可行方案说明

方案 原因
设置 ctx.Timeout = 1800 直接生效 :cross_mark: 闭源框架会强制裁剪为最大允许值(如 600)
使用 pcall 包裹规避中断 :cross_mark: 仅捕获 Lua 异常,无法阻止底层线程强制终止
多次重试短时间插件调用拼接 :cross_mark: Retimer 升级需连续性,中途断开将导致写入失败或芯片变砖

:white_check_mark: 最佳实践总结

项目 建议值
是否支持自定义超时 :white_check_mark: 支持
默认超时时间 120 秒
最大允许超时时间 600 秒(10分钟)
推荐设置值 ctx.timeout = 600
超时字段名称 timeout(小写)
是否允许超过 10 分钟 :cross_mark: 闭源限制,暂不支持
是否推荐使用插件方式升级 Retimer :white_check_mark: 是,因需独占 I2C 总线
是否应增加降级机制 :white_check_mark: 是,超时后记录日志并停止重试,防止雪崩

:pushpin: 最终建议

  1. 立即实施:将 ctx.timeout 设置为 600,并确保字段名正确(小写)
  2. 流程优化:评估升级流程是否可分段处理,减少单次耗时
  3. 异步升级架构:推动将 Retimer 升级纳入 firmware_mgmt 统一管理,使用异步任务模型
  4. 日志监控:添加关键节点打点,便于定位是 网络问题 / 写入慢 / 校验慢
  5. 联系平台方:若确需 >600 秒,请提交需求请求开放 long_running_plugin 配置选项

:white_check_mark: 结论
当前环境下无法直接设置 2 小时超时,最大有效值为 600 秒。应优先优化升级流程与时长,并通过合理配置 context.timeout=600 来保障升级完成。长远建议引入异步任务机制,避免阻塞关键总线资源。

dbus消息超时最大10分钟,没办法更长。而且独占总线10分钟也很难接受,如果总线让有其他重要的传感器如温度之类的,长时间独占总线导致温度信息无法及时更新,可能会导致更严重的问题。

如果不能修改为10分钟,那么如何实现Retimer这种固件长时间升级,但又需要独占总线的流程?