zl程序教程

您现在的位置是:首页 >  Java

当前栏目

thingsboard设备状态更新可能导致的不一致性问腿

2023-02-18 15:41:36 时间

        thingboard的概述这里就不再赘述,直接入主题讨论下thingsboard设备状态更新可能存在的不一致性问题,thingsboard有一个周期性执行的任务,该任务在DefaultDeviceStateService类的updateInactivityStateIfExpired,该任务用于更新设备的在线离线状态,当设备长时间不与tb进行交互的情况下,该任务就可以将设备的状态更新为离线。

下面看下可能存在问题的代码:

    void updateInactivityStateIfExpired(long ts, DeviceId deviceId, DeviceStateData stateData) {
        log.trace("Processing state {} for device {}", stateData, deviceId);
        if (stateData != null) {
            DeviceState state = stateData.getState();
            if (!isActive(ts, state)
                    && (state.getLastInactivityAlarmTime() == 0L || state.getLastInactivityAlarmTime() < state.getLastActivityTime())
                    && stateData.getDeviceCreationTime() + state.getInactivityTimeout() < ts) {
                if (partitionService.resolve(ServiceType.TB_CORE, stateData.getTenantId(), deviceId).isMyPartition()) {
                    state.setActive(false);
                    state.setLastInactivityAlarmTime(ts);
                    save(deviceId, ACTIVITY_STATE, false);
                    save(deviceId, INACTIVITY_ALARM_TIME, ts);
                    pushRuleEngineMessage(stateData, INACTIVITY_EVENT);
                } else {
                    cleanupEntity(deviceId);
                }
            }
        } else {
            log.debug("[{}] Device that belongs to other server is detected and removed.", deviceId);
            cleanupEntity(deviceId);
        }
    }


    boolean isActive(long ts, DeviceState state) {
        return ts < state.getLastActivityTime() + state.getInactivityTimeout();
    }

从上面代码可以tb原有代码在更新设备在线状态与设备离线时间是分成两步的,在特殊情况下可能存在更新设备状态失败但是更新设备离线时间成功的情况,毕竟不在一个事务中,这样导致的情况就是设备离线时间更新了,但是设备状态却仍然为在线状态。

这样导致的情况就是即使tb的任务想要把设备状态更新为离线,但是因为

state.getLastInactivityAlarmTime() == 0L || state.getLastInactivityAlarmTime() < state.getLastActivityTime()

永远为false而导致设备状态永远无法更新。

笔者给出一种解决方案:

在之前条件的基础上再增加一个条件:

boolean cond1 = state.isOnline() && state.getLastInactivityAlarmTime() > state.getLastActivityTime();

使用上述条件与tb原有的条件进行或操作就可以解决极端情况下设备状态永远无法离线的问题。