CritasWang opened a new pull request, #63:
URL: https://github.com/apache/iotdb-client-csharp/pull/63
Addresses the third issue raised in #61 (the `IsOpen()` semantics
discussion). Complements #62, which
fixes the two blocking defects; this PR adds the API that was deliberately
left out of that one to keep it
focused on the bugs.
对应 #61 中提出的第三个议题(`IsOpen()` 语义讨论)。与 #62 互补:#62 修复两个导致阻塞的缺陷,本 PR 新增
当时为保持该 PR 聚焦于缺陷而刻意剥离的 API。
## Why / 背景
`IsOpen()` is `!_isClose`, and `_isClose` only flips on explicit `Open()` /
`Close()`. The client keeps no
heartbeat, so a server going down never changes it. That is working as
designed and matches the Java
client — but the name reads like a health check, and users write guards such
as:
`IsOpen()` 即 `!_isClose`,只有显式 `Open()` / `Close()` 会改变它;客户端无心跳,服务端断开不会回写。
这是符合设计的(与 Java 客户端一致),但这个命名读起来像健康检查,于是用户会写出这样的守卫:
```csharp
// Never re-opens: IsOpen() stays true even while every connection is dead
if (_pool != null && _pool.IsOpen()) return;
```
Rather than change `IsOpen()` — which would be a silent behavioural break
for anyone relying on the
lifecycle meaning — this PR adds the connectivity check it is mistaken for.
与其修改 `IsOpen()`(会对依赖其生命周期语义的使用方造成无声的行为破坏),本 PR 选择新增它被误认为具备的
连通性检查能力。
## What / 实现
`SessionPool.CheckHealthAsync(CancellationToken)` issues one lightweight
request on an idle pooled
connection and returns a `SessionPoolHealth` snapshot (`Status`,
`AvailableClients`, `TotalPoolSize`,
`FailedReconnections`, `Message`, `Error`).
`SessionPool.CheckHealthAsync(CancellationToken)` 在空闲连接上发送一次轻量请求,返回
`SessionPoolHealth`
快照(状态、可用连接数、池容量、重连失败次数、说明、底层异常)。
```csharp
var health = await sessionPool.CheckHealthAsync();
if (!health.IsHealthy)
{
logger.LogWarning("{Health}", health); // "Unhealthy: The server did
not answer the probe: ..."
}
```
| `SessionPoolHealthStatus` | Meaning / 含义
|
| ------------------------- |
-------------------------------------------------------------------------------------
|
| `NotOpen` | Pool not opened, or already closed. No network
call is attempted. 池未打开或已关闭,不发起网络调用 |
| `Healthy` | The server answered the probe. 服务端已响应探测
|
| `Degraded` | Open, but no idle connection to probe with.
已打开但无空闲连接可探测 |
| `Unhealthy` | A connection was available but the server did
not answer. 有可用连接但服务端未响应 |
Design decisions worth reviewing / 需要评审关注的设计决策:
- **The probe never blocks.** `ConcurrentClientQueue.TryTake` is added for
this. A health endpoint must not
queue behind application load, so when every client is busy the probe
returns `Degraded` at once rather
than waiting. This also keeps the probe independent of the pool wait
timeout fixed in #62.
**探针永不阻塞**:为此新增 `ConcurrentClientQueue.TryTake`。健康检查端点不应排在业务负载之后,所以所有
连接繁忙时立即返回 `Degraded`。这也使探针不依赖 #62 中修复的池等待超时。
- **`Degraded` is deliberately not a server verdict.** It only means nothing
was idle at that instant.
Treating saturation as an outage would make the check useless under load.
**`Degraded` 刻意不表示服务端故障**,只表示当时没有空闲连接。把饱和当作故障会让该检查在高负载下失去意义。
- **The borrowed connection is always returned, and a failed probe does not
close it.** The existing
reconnect-on-use path still handles the dead connection on the next real
operation, so the probe has no
side effects on pool state.
**借出的连接总会归还,探测失败也不关闭它**:失效连接仍由既有的按需重连路径在下次真实操作时处理,探针
对池状态无副作用。
- **No implicit timeout.** Callers bound the probe with a
`CancellationToken` if they want to; adding a
hidden default felt worse than making it explicit. Happy to add one if
reviewers disagree.
**不设隐式超时**:调用方可用 `CancellationToken` 自行限时。相比隐藏的默认值,显式更好。若评审有不同
意见,可以加上。
`TableSessionPool` forwards the method with identical semantics.
`TableSessionPool` 以相同语义转发该方法。
## Relationship to #62 / 与 #62 的关系
Both branch from `main` and are independently mergeable. They touch
`ConcurrentClientQueue.cs`,
`SessionPool.cs` and the same two docs, so whichever merges second will need
a trivial rebase — the changes
are additive and do not overlap semantically (#62 fixes the wait timeout and
slot accounting; this PR adds
a probe path).
两者均基于 `main` 且可独立合并。它们都改动了 `ConcurrentClientQueue.cs`、`SessionPool.cs` 和同样的两份
文档,因此后合并的一方需要一次简单的 rebase——改动是叠加式的、语义上不重叠(#62 修复等待超时与槽位记账,
本 PR 新增探测路径)。
Suggested order: merge #62 first (it fixes user-facing hangs), then rebase
this one.
建议顺序:先合并 #62(它修复的是用户可见的卡死),再 rebase 本 PR。
## Tests / 测试
`SessionPoolHealthTests` covers the `NotOpen` path (asserting no network
call is attempted and the call
returns promptly), the non-blocking `TryTake` semantics, and the
`SessionPoolHealth` snapshot itself.
`SessionPoolHealthTests` 覆盖 `NotOpen` 路径(断言不发起网络调用且立即返回)、`TryTake` 的非阻塞语义,
以及 `SessionPoolHealth` 快照本身。
`dotnet test tests/Apache.IoTDB.Tests` — 29 passed, 0 failed. `dotnet build
Apache.IoTDB.sln` — 0 errors.
`dotnet format --verify-no-changes` — clean.
The `Healthy` / `Unhealthy` transitions need a live server and are left to
the e2e suite rather than
simulated with a mock transport.
`Healthy` / `Unhealthy` 的状态转换需要真实服务端,交由 e2e 套件覆盖,未用 mock transport 模拟。
Note: the unit tests were executed locally against `net8.0` because no .NET
5 arm64 runtime is available on
this machine; the committed `TargetFramework` is unchanged at `net5.0`.
说明:本机没有 .NET 5 的 arm64 运行时,单元测试在本地以 `net8.0` 执行;提交的 `TargetFramework` 仍为
`net5.0`。
## Docs / 文档
- `docs/SessionPool_Exception_Handling.md` — new section contrasting
`CheckHealthAsync` with `IsOpen`, the
status table, behaviour notes, and the existing health-check example
rewritten to delegate to the
built-in probe.
`docs/SessionPool_Exception_Handling.md` —— 新增对比 `CheckHealthAsync` 与
`IsOpen` 的章节、状态表、
行为说明,并将原有的健康检查示例改写为委托给内置探针。
- `docs/API.md` — added the `CheckHealthAsync` row and clarified `IsOpen`.
`docs/API.md` —— 新增 `CheckHealthAsync` 一行并澄清 `IsOpen`。
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]