)]}'
{
  "commit": "d3266549eae7b1cf367c756c1b03e560f61e4963",
  "tree": "acc32d047cb708acf5ec6fb23ed1be1b767acf30",
  "parents": [
    "178ebb07bf284033921c606ca3446b64f2cd2eec"
  ],
  "author": {
    "name": "CritasWang",
    "email": "critas@outlook.com",
    "time": "Tue Sep 22 14:44:03 2026 +0800"
  },
  "committer": {
    "name": "GitHub",
    "email": "noreply@github.com",
    "time": "Tue Sep 22 14:44:03 2026 +0800"
  },
  "message": "Add SessionPool.CheckHealthAsync connectivity probe (#63)\n\n新增 SessionPool.CheckHealthAsync 连通性探针\n\nIsOpen() is a lifecycle flag - it reports whether the caller has opened the pool\nand not yet closed it. Because the client keeps no heartbeat, it stays true after\nthe server goes down, and users routinely mistake it for a health check, e.g.\n`if (pool.IsOpen()) return;` in a lazy-open guard, which then never rebuilds the\npool. This adds the connectivity check that IsOpen() is mistaken for, without\nchanging IsOpen() itself.\nIsOpen() 是生命周期标志，仅表示调用方是否已打开且尚未关闭连接池。由于客户端无心跳，\n服务端断开后它仍为 true，用户普遍将其误当作健康检查（例如惰性打开守卫里的\n`if (pool.IsOpen()) return;`），从而导致连接池永远不会被重建。本提交新增了\nIsOpen() 被误认为具备的连通性检查能力，且不改变 IsOpen() 自身行为。\n\n- Add SessionPool.CheckHealthAsync(CancellationToken), which issues one lightweight\n  request on an idle pooled connection and returns a SessionPoolHealth snapshot\n  carrying Status, AvailableClients, TotalPoolSize, FailedReconnections, Message\n  and the underlying Error.\n  新增 SessionPool.CheckHealthAsync(CancellationToken)：在空闲连接上发送一次轻量请求，\n  返回包含状态、可用连接数、池容量、重连失败次数、说明和底层异常的 SessionPoolHealth 快照。\n\n- Add SessionPoolHealthStatus with four outcomes: NotOpen (no network call is made),\n  Healthy, Degraded (open but no idle connection to probe with - a saturation signal,\n  not a server verdict) and Unhealthy (a connection was available but the server did\n  not answer).\n  新增 SessionPoolHealthStatus 四种结果：NotOpen（不发起网络调用）、Healthy、\n  Degraded（池已打开但无空闲连接可用于探测，表示饱和而非服务端故障）、\n  Unhealthy（有可用连接但服务端未响应）。\n\n- Add ConcurrentClientQueue.TryTake so the probe never blocks. A health endpoint\n  must not queue behind application load, so when every client is busy the probe\n  returns Degraded immediately instead of waiting.\n  新增 ConcurrentClientQueue.TryTake 使探针永不阻塞：健康检查端点不应排在业务负载之后，\n  因此所有连接繁忙时立即返回 Degraded 而不是等待。\n\n- The borrowed connection is always returned to the pool and a failed probe does not\n  close it, so the existing reconnect-on-use path is unchanged.\n  借出的连接总会归还池中，探测失败也不会关闭它，因此既有的按需重连路径保持不变。\n\n- Forward CheckHealthAsync from TableSessionPool with identical semantics.\n  TableSessionPool 以相同语义转发 CheckHealthAsync。\n\n- Add tests for the NotOpen path, non-blocking TryTake semantics and the health\n  snapshot; document the API in docs/SessionPool_Exception_Handling.md and docs/API.md.\n  补充 NotOpen 路径、TryTake 非阻塞语义与健康快照的测试；在相关文档中说明该 API。",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "43fdd0487238e5d7da8f88c0e998752ec5d100af",
      "old_mode": 33188,
      "old_path": "docs/API.md",
      "new_id": "0b890b0542667e58e55bd269a45a127a30614925",
      "new_mode": 33188,
      "new_path": "docs/API.md"
    },
    {
      "type": "modify",
      "old_id": "99039de6157d339e80561ea7d21b3d051114985c",
      "old_mode": 33188,
      "old_path": "docs/SessionPool_Exception_Handling.md",
      "new_id": "c9f0deec2a9b3210e4619037a0645147231eceae",
      "new_mode": 33188,
      "new_path": "docs/SessionPool_Exception_Handling.md"
    },
    {
      "type": "modify",
      "old_id": "f59b631d0cd49b2c36d079555ac53432bae5d2ba",
      "old_mode": 33188,
      "old_path": "src/Apache.IoTDB/ConcurrentClientQueue.cs",
      "new_id": "12bb087659f6a24bcaf7c1300f03d0912ce8d21b",
      "new_mode": 33188,
      "new_path": "src/Apache.IoTDB/ConcurrentClientQueue.cs"
    },
    {
      "type": "modify",
      "old_id": "fff1ea3bada4e644c974ca371be89ba03c135c0c",
      "old_mode": 33188,
      "old_path": "src/Apache.IoTDB/SessionPool.cs",
      "new_id": "f5747d435295d830d38e5b989adfd6e0d720decb",
      "new_mode": 33188,
      "new_path": "src/Apache.IoTDB/SessionPool.cs"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "691d3fdca50c1a2afa552584c1396eec0a83116a",
      "new_mode": 33188,
      "new_path": "src/Apache.IoTDB/SessionPoolHealth.cs"
    },
    {
      "type": "modify",
      "old_id": "921aba165b11dddd578f5dcf05a909aa2ce6cbf8",
      "old_mode": 33188,
      "old_path": "src/Apache.IoTDB/TableSessionPool.cs",
      "new_id": "3d39e0c384be2f2c28e019169000bcb7666827f6",
      "new_mode": 33188,
      "new_path": "src/Apache.IoTDB/TableSessionPool.cs"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "16a608923fdf0d4456e2abea901a8c423ec21240",
      "new_mode": 33188,
      "new_path": "tests/Apache.IoTDB.Tests/SessionPoolHealthTests.cs"
    }
  ]
}
