You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

node-opcua客户端批量监控多OPC UA节点失效问题问询

node-opcua批量监控节点异常:仅部分节点被成功监控

当前行为

使用forEach循环批量监控OPC UA节点时,待监控数组包含5个节点,但不同版本的node-opcua存在监控节点不全的问题:

  • node-opcua 2.30.0:仅能监控2个节点
  • node-opcua 2.72.2:仅能监控1个节点
    对比UA Expert工具,所有5个节点均可正常被监控。

预期行为

所有待监控的OPC UA节点均能被正常监控,并在数据变化时接收通知。

复现代码

const idsToMonitor = ["ns=4;i=16", "ns=4;i=17", "ns=4;i=11", "ns=4;i=12", "ns=4;i=18"]
const monitoringParamaters = {
        samplingInterval: 100,
        discardOldest: true,
        queueSize: 10,
    };
    idsToMonitor.forEach((nodeId) => {
        opc_subscription.monitor({
            nodeId: resolveNodeId(nodeId),
            attributeId: AttributeIds.Value,
        },
        monitoringParamaters,
        TimestampsToReturn.Both,
        (err, monitoredItem) => {
            monitoredItem.on("changed", function (dataValue) {
            var Node = {nodeId: nodeId, nodeName: "111" , nodeValue: dataValue.value.value , nodeTimestamp: dataValue.sourceTimestamp.toISOString()};
            console.log(JSON.stringify(Node));
        });
    });
});

环境信息

  • node-opcua角色:OPC UA客户端
  • 安装方式:npm包安装
  • 操作系统:Windows 10
  • Node.js版本:16.16.0

问题原因

forEach循环会同步触发所有opc_subscription.monitor异步调用,短时间内大量并发请求可能被OPC UA服务器限流,或node-opcua客户端内部因请求积压导致部分监控项创建失败。

修复方案

推荐使用批量创建监控项的API,这是node-opcua官方支持的规范操作方式,效率更高且能避免并发问题:

const idsToMonitor = ["ns=4;i=16", "ns=4;i=17", "ns=4;i=11", "ns=4;i=12", "ns=4;i=18"];
const monitoringParameters = {
    samplingInterval: 100,
    discardOldest: true,
    queueSize: 10,
};

// 构造批量监控项参数
const itemsToMonitor = idsToMonitor.map(nodeId => ({
    nodeId: resolveNodeId(nodeId),
    attributeId: AttributeIds.Value,
}));

// 调用批量创建API
opc_subscription.createMonitoredItems(
    TimestampsToReturn.Both,
    itemsToMonitor.map(item => ({ 
        itemToMonitor: item, 
        monitoringParameters: monitoringParameters 
    })),
    (err, results) => {
        if (err) {
            console.error("批量创建监控项失败:", err);
            return;
        }

        results.forEach((result, index) => {
            const targetNodeId = idsToMonitor[index];
            if (result.statusCode !== StatusCodes.Good) {
                console.error(`节点${targetNodeId}监控创建失败:${result.statusCode}`);
                return;
            }

            const monitoredItem = result.monitoredItem;
            monitoredItem.on("changed", (dataValue) => {
                const nodeData = {
                    nodeId: targetNodeId,
                    nodeName: "111",
                    nodeValue: dataValue.value.value,
                    nodeTimestamp: dataValue.sourceTimestamp.toISOString()
                };
                console.log(JSON.stringify(nodeData));
            });
        });
    }
);

如果需要严格串行创建监控项(适用于特殊场景),可使用异步循环:

const idsToMonitor = ["ns=4;i=16", "ns=4;i=17", "ns=4;i=11", "ns=4;i=12", "ns=4;i=18"];
const monitoringParameters = {
    samplingInterval: 100,
    discardOldest: true,
    queueSize: 10,
};

async function createMonitoredItemsSequentially() {
    for (const nodeId of idsToMonitor) {
        await new Promise((resolve, reject) => {
            opc_subscription.monitor({
                nodeId: resolveNodeId(nodeId),
                attributeId: AttributeIds.Value,
            }, monitoringParameters, TimestampsToReturn.Both, (err, monitoredItem) => {
                if (err) {
                    console.error(`节点${nodeId}监控创建失败:`, err);
                    reject(err);
                    return;
                }

                monitoredItem.on("changed", (dataValue) => {
                    const nodeData = {
                        nodeId: nodeId,
                        nodeName: "111",
                        nodeValue: dataValue.value.value,
                        nodeTimestamp: dataValue.sourceTimestamp.toISOString()
                    };
                    console.log(JSON.stringify(nodeData));
                });
                resolve();
            });
        });
    }
}

// 执行串行创建
createMonitoredItemsSequentially().catch(err => console.error("串行创建监控项失败:", err));

说明

  • createMonitoredItems会将所有监控请求合并为一个批量请求发送给服务器,符合OPC UA协议规范,能有效避免并发请求导致的限流问题。
  • 串行方式虽然可靠,但效率低于批量创建,仅建议在特定场景下使用。

内容的提问来源于stack exchange,提问作者Abdelhak Sidi Ali Mebarek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 00:06:23