Safe API — 永不抛异常变体
概述
UI 主线程 / 批量轮询不希望被一条 RPC 失败抛出的 OpcUaException 中断, SDK 为常用调用各提供一个 *_safe 版本 — 任何异常折叠为 StatusCode, 调用方用 (status, value) 元组判读, 不再写 try/except。
对应规范段: Browse Part 4 §5.8, Read §5.10.2, Write §5.10.4, Call §5.11.2, HistoryRead Part 11 §6.5。
API
| 方法 | 类别 | 读写 | 说明 |
|---|---|---|---|
| ua.browse_safe(node_id, filter) | 浏览 | 读 | 返回 (StatusCode, list[OpcUaReference]) |
| ua.read_safe(node_id, attribute) | 读 | 读 | 返回 (StatusCode, DataValue), 失败时 value=None |
| ua.write_safe(node_id, value, attribute) | 写 | 写 | 返回 StatusCode |
| ua.call_safe(object_id, method_id, *inputs) | 方法 | 写 | 返回 (StatusCode, list[Variant]) |
| ua.read_history_safe(node_id, t0, t1, max) | 历史 | 读 | 返回 (StatusCode, list[DataValue]) |
代码示例
from opcua import DarraOpcUa, StatusCode, Variant
with DarraOpcUa("opc.tcp://localhost:4840") as ua:
ua.connect()
# 1) 浏览 - 节点删除不让全树报错
st, refs = ua.browse_safe("ns=2;s=Boiler1")
if st != StatusCode.GOOD:
print(f"Browse 失败 {st}, 跳过")
else:
for r in refs:
print(r.browse_name)
# 2) 批量轮询 - 单点失败不打断
for nid in node_list:
rs, dv = ua.read_safe(nid)
if rs == StatusCode.GOOD and dv is not None:
print(f"{nid} = {dv.value}")
else:
print(f"{nid} = <{rs}>")
# 3) 批量下发参数
for nid, val in setpoints.items():
rc = ua.write_safe(nid, Variant(val))
if rc != StatusCode.GOOD:
print(f"写 {nid} 失败 {rc}")
# 4) 调用方法
cst, outs = ua.call_safe("ns=2;s=Robot", "ns=2;s=Robot.Home")
if cst != StatusCode.GOOD:
print(f"Home 失败: {cst}")
# 5) 历史读
hst, vals = ua.read_history_safe("ns=2;s=Temp", t0, t1, max_values=5000)
与重试机制的关系
普通 read/write/browse/call/read_history 内部都包了 _retry_on_session_fault, session 级故障 (BadSessionClosed) 会自动重连一次。Safe 变体调用同一套核心方法, 也会受益于自动重连。
最佳实践
- UI 主线程一律用 Safe — 异常逃逸会让进程挂掉
- 批处理 / 巡检循环用 Safe — 单点失败不阻塞整体
- 业务关键路径仍用普通版本, 让异常显式暴露
跨语言对照
| C# | Python | Java | C++ | Rust | C |
|---|---|---|---|---|---|
| BrowseSafe | browse_safe | browseSafe | BrowseSafe | browse_safe | DarraUa_Session_BrowseSafe |
| ReadSafe | read_safe | readSafe | ReadSafe | read_safe | DarraUa_Session_ReadSafe |
| WriteSafe | write_safe | writeSafe | WriteSafe | write_safe | DarraUa_Session_WriteSafe |
| CallSafe | call_safe | callSafe | CallSafe | call_safe | DarraUa_Session_CallSafe |
| ReadHistorySafe | read_history_safe | readHistorySafe | ReadHistorySafe | read_history_safe | DarraUa_Session_ReadHistorySafe |