Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions .github/workflows/session-soak.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: session-soak

on:
workflow_dispatch:
inputs:
duration_minutes:
description: Bounded soak duration
type: choice
options: ["1", "5", "15", "20"]
default: "5"
seed:
description: Positive 32-bit seed; 0 derives one from the run ID
type: string
default: "0"
schedule:
- cron: "43 2 * * 3"

permissions:
contents: read

concurrency:
group: session-soak
cancel-in-progress: false

jobs:
session-soak:
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@v7
- uses: actions/setup-dotnet@v6
with:
dotnet-version: 8.0.x
- name: Resolve bounded run parameters
id: parameters
shell: bash
env:
INPUT_DURATION_MINUTES: ${{ inputs.duration_minutes || '15' }}
INPUT_SEED: ${{ inputs.seed || '0' }}
run: |
set -euo pipefail
if ! [[ "$INPUT_SEED" =~ ^[0-9]+$ ]] || (( INPUT_SEED > 2147483647 )); then
echo "seed must be between 0 and 2147483647" >&2
exit 2
fi
seed="$INPUT_SEED"
if (( seed == 0 )); then
seed=$((GITHUB_RUN_ID % 2147483647))
if (( seed == 0 )); then seed=1; fi
fi
duration_seconds=$((INPUT_DURATION_MINUTES * 60))
echo "seed=$seed" >> "$GITHUB_OUTPUT"
echo "duration_seconds=$duration_seconds" >> "$GITHUB_OUTPUT"
- name: Build soak harness
run: dotnet build test/SecsFrame.Soak/SecsFrame.Soak.csproj -c Release
- name: Run session fault soak
run: >-
dotnet run --project test/SecsFrame.Soak/SecsFrame.Soak.csproj
-c Release --no-build --
--seed ${{ steps.parameters.outputs.seed }}
--duration-seconds ${{ steps.parameters.outputs.duration_seconds }}
--max-cycles 10000
--output artifacts/soak/session-soak.jsonl
- name: Upload reproduction report
if: always()
uses: actions/upload-artifact@v6
with:
name: session-soak-${{ github.run_id }}-${{ steps.parameters.outputs.seed }}
path: artifacts/soak/session-soak.jsonl
if-no-files-found: error
retention-days: 14
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@

### 新增

- 增加独立 <code>SecsFrame.Soak</code> 可执行程序,在真实 TCP 待处理事务中
按显式随机种子选择双方 Separate 或端点销毁重建,恢复 Selected 后立即
验证新事务;普通 <code>dotnet test</code> 不执行该长时负载。
- 增加手动和每周定时的 <code>session-soak</code> 工作流,固定 20 分钟程序
上限、25 分钟作业上限和每周期 20 秒上限;成功或失败均上传包含 commit、
运行时、seed、故障序列和结果的 JSONL,保留 14 天。
- 增加真实 TCP Active/Passive 重复会话抖动故障注入测试;固定三轮断开与
重选并复用相同 System Bytes,验证待处理事务确定中断、旧回复与强制迟到
T3 回调不污染替换会话,且新事务可成功完成。
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ Item 用法与边界见
[docs/HSMS-SESSION-STATE-MACHINE.md](docs/HSMS-SESSION-STATE-MACHINE.md),
数据事务边界见
[docs/HSMS-DATA-TRANSACTIONS.md](docs/HSMS-DATA-TRANSACTIONS.md),
独立长时会话故障注入见
[docs/HSMS-SOAK.md](docs/HSMS-SOAK.md),
公共连接用法见
[docs/HSMS-CONNECTION.md](docs/HSMS-CONNECTION.md),
结构化故障分类见
Expand Down
1 change: 1 addition & 0 deletions SecsFrame.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
</Folder>
<Folder Name="/test/">
<Project Path="test/SecsFrame.Secs4NetInterop.Tests/SecsFrame.Secs4NetInterop.Tests.csproj" />
<Project Path="test/SecsFrame.Soak/SecsFrame.Soak.csproj" />
<Project Path="test/SecsFrame.Tests/SecsFrame.Tests.csproj" />
</Folder>
</Solution>
11 changes: 8 additions & 3 deletions docs/DEVELOPMENT-STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ GitHub Issue/Actions:
- 真实 TCP Active/Passive 事务测试固定重复三次断开和重选,复用相同
System Bytes 并强制投递旧 T3 回调,验证旧回复、旧计时器和待处理事务
不会污染替换会话。
- 独立 <code>SecsFrame.Soak</code> 和 <code>session-soak</code> 工作流提供
显式 seed、四类真实 TCP 故障、程序/周期/作业三层上限及 14 天 JSONL
产物;普通 CI 只编译 harness,不运行长时负载。
- 最近一次完整本地验证中,核心测试在 `net48`、`net8.0`、`net10.0` 各
通过 289 项;官方 secs4net 互操作测试在 `net8.0`、`net10.0` 各通过
2 项。
Expand Down Expand Up @@ -85,9 +88,11 @@ Primary/Secondary、断开和重选,并验证:
- 测试时间有严格上限,可稳定进入现有普通 CI。

这个切片只增加故障注入测试和必要的测试支撑,不改变协议默认值或公共 API。
下一可执行项是评估不进入普通 CI 的独立定时工作流:先固定运行上限、随机
种子、故障重现信息和产物保留边界,再增加长时间 soak 与随机网络故障。
该工作流不得引入新的协议默认值,也不能替代确定性回归和完整普通 CI。
独立定时工作流已经落地。合并后应先以 <code>workflow_dispatch</code> 使用
固定 seed <code>12345</code> 运行 5 分钟,核对四种故障均出现、JSONL 可下载
且失败定位信息完整;随后观察至少三次每周定时运行,再决定是否增加 TCP
half-close、reset 或跨平台矩阵。扩大故障范围前必须保持固定运行上限和可
重现输入,也不能用 soak 替代确定性回归和完整普通 CI。

## 状态更新规则

Expand Down
7 changes: 7 additions & 0 deletions docs/HSMS-DATA-TRANSACTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ Active/Passive 双端真实 TCP 回环另行覆盖 Select 后的 Primary/Seconda
会话回复,验证待处理事务确定中断且替换会话仍可完成本代事务。同步只使用
状态事件、计时器武装信号和事务任务,并由统一取消令牌严格封顶。

独立 <code>SecsFrame.Soak</code> 可执行程序进一步在真实 TCP 待处理事务中
按 seed 随机选择 Active Separate、Passive Separate、Active 端点销毁重建
或 Passive 端点销毁重建。每次故障后必须重新进入 Selected 并完成新事务,
逐周期 JSONL 保留故障类型、中断异常和新旧 System Bytes。该负载只由手动/
定时工作流运行,不进入普通 <code>dotnet test</code>;完整运行与复现边界见
[HSMS-SOAK.md](HSMS-SOAK.md)。

这些测试是自主构造的工程向量,不是 SEMI 一致性测试。

## 标准核对边界
Expand Down
68 changes: 68 additions & 0 deletions docs/HSMS-SOAK.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# HSMS 会话故障 Soak

## 范围

<code>SecsFrame.Soak</code> 是独立的真实 TCP 工程故障注入程序。它加入
solution 以便普通构建持续检查,但不是测试项目,因此
<code>dotnet test SecsFrame.slnx</code> 不会执行长时负载。

每个周期先从 Active 端发送带 W-Bit 的 Primary,并在 Passive 端收到但尚未
回复时,按显式随机 seed 选择一种故障:

- Active 发送 Separate;
- Passive 发送 Separate;
- 销毁并重建 Active 公共连接;
- 销毁并重建 Passive 公共连接。

原事务必须以运输/会话中断结束。双方重新进入 Selected 后,程序立即执行
新的 Primary/Secondary 往返并核对动态 Body。程序按 seed 对每组四种故障
洗牌,因此每四个完整周期覆盖全部模式且顺序可复现;程序不使用设备输入、
厂商兼容开关或新的协议默认值。

## 运行边界

独立 [session-soak 工作流](../.github/workflows/session-soak.yml) 支持:

- 每周三 UTC 02:43 定时运行 15 分钟;
- 手动选择 1、5、15 或 20 分钟;
- 手动指定正 32 位 seed,<code>0</code> 从 GitHub Run ID 确定性派生;
- 程序最长 20 分钟、单周期最长 20 秒、作业最长 25 分钟;
- 同一时间只运行一个 soak 作业,后续触发排队而不取消已有运行。

普通 PR/push CI 不触发该工作流。它仍会通过 solution 的 Release 构建检查
harness 是否可编译;协议向量、状态机测试和 secs4net 互操作门禁保持不变。

## 本地复现

~~~bash
dotnet build test/SecsFrame.Soak/SecsFrame.Soak.csproj -c Release
dotnet run --project test/SecsFrame.Soak/SecsFrame.Soak.csproj \
-c Release --no-build -- \
--seed 12345 \
--duration-seconds 300 \
--max-cycles 10000 \
--output artifacts/soak/session-soak.jsonl
~~~

<code>--seed</code> 必须显式提供;duration 接受 1 到 1200 秒,max-cycles
接受 1 到 100000。达到任一上限即成功停止。若总时限在周期中到达,程序
取消该周期、释放双方连接并写出 <code>durationElapsed</code> 完成记录;若
时限内没有任何周期完成则失败,避免初始化停滞被误记为成功。

## 产物与复现

JSONL 在启动、每个周期开始、每个周期完成、失败和正常结束时立即刷新。
启动记录包含 Git commit、.NET 运行时、OS、seed、duration 与 max-cycles;
周期记录包含故障类型、中断异常类型、原事务和恢复事务的 System Bytes 及
耗时。失败记录包含 seed、周期、故障类型和异常文本。

工作流无论成功失败都上传该文件,保留 14 天。复现时应检出启动记录中的
commit,使用相同运行时、OS、seed、duration 和 max-cycles;最后一个
<code>cycleStarted</code> 给出失败前选择的确切故障。报告只包含程序生成的
周期标记和协议/运行期元数据,不捕获设备 Body、原始 TCP 字节或异常帧。

## 证据边界

固定 seed 的本地短时验证必须至少覆盖四种故障并确认 duration 上限正常
收口。定时 soak 用于发现长期资源、监听恢复和竞态问题,不替代普通 CI、
确定性状态机/协议向量或跨实现测试,也不构成 SEMI 一致性或生产稳定性声明。
2 changes: 2 additions & 0 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
确定的取消/释放语义。
- [x] 使用 nuget.org 官方 Secs4Net 3.1.0 的 Active/Passive、Select、
双方 Linktest 和双方 Primary/Secondary 跨实现测试。
- [x] 不进入普通测试的可复现会话 soak:手动/定时触发、固定上限、显式
seed、四类真实 TCP 故障和失败产物保留。
- [x] 公共结构化诊断模型,覆盖运输、协议、会话、事务和解码故障。
- [x] 运行期 Primary 路由与可释放处理器注册,不依赖预生成消息类型。
- [ ] 使用授权 E37/E37.1 核对 T5/T8 默认值与精确启停边界。
Expand Down
Loading
Loading