[harmonyhub] Fix reliability issues (#13702)

* Fix compiler info

Unsafe interpretation of method return type as '@NonNull' based on the receiver type 'java.util.Enumeration<java.net.@NonNull NetworkInterface>'. Type 'java.util.Enumeration<E>' doesn't seem to be designed with null type annotations in mind

* Improve robustness of job rescheduling and handler disposal

Handler tried updating thing although the handler was already disposed

Fixes #13701

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
This commit is contained in:
Jacob Laursen 2022-11-17 20:48:28 +01:00 committed by GitHub
parent b6f9f6339e
commit ea49488b86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 15 additions and 13 deletions

View File

@ -171,6 +171,7 @@ public class HarmonyHubDiscoveryService extends AbstractDiscoveryService {
// Broadcast the message over all the network interfaces // Broadcast the message over all the network interfaces
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) { while (interfaces.hasMoreElements()) {
@Nullable
NetworkInterface networkInterface = interfaces.nextElement(); NetworkInterface networkInterface = interfaces.nextElement();
if (networkInterface.isLoopback() || !networkInterface.isUp()) { if (networkInterface.isLoopback() || !networkInterface.isUp()) {
continue; continue;

View File

@ -22,7 +22,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -75,7 +75,7 @@ public class HarmonyHubHandler extends BaseBridgeHandler implements HarmonyClien
private final Logger logger = LoggerFactory.getLogger(HarmonyHubHandler.class); private final Logger logger = LoggerFactory.getLogger(HarmonyHubHandler.class);
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(HARMONY_HUB_THING_TYPE); public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(HARMONY_HUB_THING_TYPE);
private static final Comparator<Activity> ACTIVITY_COMPERATOR = Comparator.comparing(Activity::getActivityOrder, private static final Comparator<Activity> ACTIVITY_COMPERATOR = Comparator.comparing(Activity::getActivityOrder,
Comparator.nullsFirst(Integer::compareTo)); Comparator.nullsFirst(Integer::compareTo));
@ -84,7 +84,7 @@ public class HarmonyHubHandler extends BaseBridgeHandler implements HarmonyClien
private static final int HEARTBEAT_INTERVAL = 30; private static final int HEARTBEAT_INTERVAL = 30;
// Websocket will timeout after 60 seconds, pick a sensible max under this, // Websocket will timeout after 60 seconds, pick a sensible max under this,
private static final int HEARTBEAT_INTERVAL_MAX = 50; private static final int HEARTBEAT_INTERVAL_MAX = 50;
private List<HubStatusListener> listeners = new CopyOnWriteArrayList<>(); private Set<HubStatusListener> listeners = ConcurrentHashMap.newKeySet();
private final HarmonyHubHandlerFactory factory; private final HarmonyHubHandlerFactory factory;
private @NonNullByDefault({}) HarmonyHubConfig config; private @NonNullByDefault({}) HarmonyHubConfig config;
private final HarmonyClient client; private final HarmonyClient client;
@ -184,7 +184,6 @@ public class HarmonyHubHandler extends BaseBridgeHandler implements HarmonyClien
@Override @Override
public void initialize() { public void initialize() {
config = getConfigAs(HarmonyHubConfig.class); config = getConfigAs(HarmonyHubConfig.class);
cancelRetry();
updateStatus(ThingStatus.UNKNOWN); updateStatus(ThingStatus.UNKNOWN);
scheduleRetry(0); scheduleRetry(0);
} }
@ -294,29 +293,31 @@ public class HarmonyHubHandler extends BaseBridgeHandler implements HarmonyClien
} }
private void disconnectFromHub() { private void disconnectFromHub() {
ScheduledFuture<?> localHeartBeatJob = heartBeatJob; ScheduledFuture<?> heartBeatJob = this.heartBeatJob;
if (localHeartBeatJob != null && !localHeartBeatJob.isDone()) { if (heartBeatJob != null) {
localHeartBeatJob.cancel(false); heartBeatJob.cancel(true);
this.heartBeatJob = null;
} }
client.disconnect(); client.disconnect();
} }
private void setOfflineAndReconnect(String error) { private void setOfflineAndReconnect(String error) {
disconnectFromHub(); disconnectFromHub();
scheduleRetry(RETRY_TIME);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, error); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, error);
scheduleRetry(RETRY_TIME);
} }
private void cancelRetry() { private void cancelRetry() {
ScheduledFuture<?> localRetryJob = retryJob; ScheduledFuture<?> retryJob = this.retryJob;
if (localRetryJob != null && !localRetryJob.isDone()) { if (retryJob != null) {
localRetryJob.cancel(false); retryJob.cancel(true);
this.retryJob = null;
} }
} }
private synchronized void scheduleRetry(int retrySeconds) { private synchronized void scheduleRetry(int delaySeconds) {
cancelRetry(); cancelRetry();
retryJob = scheduler.schedule(this::connect, retrySeconds, TimeUnit.SECONDS); retryJob = scheduler.schedule(this::connect, delaySeconds, TimeUnit.SECONDS);
} }
private void updateState(@Nullable Activity activity) { private void updateState(@Nullable Activity activity) {