Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[openhabcloud] Reconnection Fixes #14251

Merged
merged 7 commits into from
Jan 29, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
digitaldan marked this conversation as resolved.
Show resolved Hide resolved
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
digitaldan marked this conversation as resolved.
Show resolved Hide resolved
import java.util.concurrent.atomic.AtomicReference;

import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
Expand All @@ -51,6 +54,7 @@
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
import io.socket.engineio.client.Transport;
import io.socket.engineio.client.transports.WebSocket;
import io.socket.parser.Packet;
import io.socket.parser.Parser;
import okhttp3.OkHttpClient.Builder;
Expand All @@ -68,6 +72,15 @@
* @author Kai Kreuzer - migrated code to new Jetty client and ESH APIs
*/
public class CloudClient {

private static final long RECONNECT_MIN = 1_000;

private static final long RECONNECT_MAX = 60_000;

private static final double RECONNECT_JITTER = 0.5;

private static final long READ_TIMEOUT = 60_0000;

/*
* Logger for this class
*/
Expand Down Expand Up @@ -108,11 +121,6 @@ public class CloudClient {
*/
private boolean isConnected;

/*
* This variable holds version of local openHAB
*/
private String openHABVersion;
ssalonen marked this conversation as resolved.
Show resolved Hide resolved

/*
* This variable holds instance of Socket.IO client class which provides communication
* with the openHAB Cloud
Expand All @@ -139,11 +147,15 @@ public class CloudClient {

/*
* Delay reconnect scheduler pool
*
*
*/
protected final ScheduledExecutorService scheduler = ThreadPoolManager
.getScheduledPool(ThreadPoolManager.THREAD_POOL_NAME_COMMON);

@SuppressWarnings("null")
private final AtomicReference<Optional<ScheduledFuture<?>>> reconnectFuture = new AtomicReference<>(
Optional.empty());

/**
* Constructor of CloudClient
*
Expand All @@ -161,9 +173,9 @@ public CloudClient(HttpClient httpClient, String uuid, String secret, String bas
this.remoteAccessEnabled = remoteAccessEnabled;
this.exposedItems = exposedItems;
this.jettyClient = httpClient;
reconnectBackoff.setMin(1000);
reconnectBackoff.setMax(30_000);
reconnectBackoff.setJitter(0.5);
reconnectBackoff.setMin(RECONNECT_MIN);
digitaldan marked this conversation as resolved.
Show resolved Hide resolved
reconnectBackoff.setMax(RECONNECT_MAX);
reconnectBackoff.setJitter(RECONNECT_JITTER);
}

/**
Expand All @@ -173,17 +185,25 @@ public CloudClient(HttpClient httpClient, String uuid, String secret, String bas
public void connect() {
try {
Options options = new Options();
options.transports = new String[] { WebSocket.NAME };
options.reconnection = true; // default value true
options.reconnectionAttempts = Integer.MAX_VALUE;
options.reconnectionDelay = RECONNECT_MIN; // default value 1_000
options.reconnectionDelayMax = RECONNECT_MAX; // default value 5_000
options.randomizationFactor = RECONNECT_JITTER; // default value 0.5
options.timeout = READ_TIMEOUT; // default value 20_000
Builder okHttpBuilder = new Builder();
okHttpBuilder.readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS); // default 10_000
if (logger.isTraceEnabled()) {
// When trace level logging is enabled, we activate further logging of HTTP calls
// of the Socket.IO library
Builder okHttpBuilder = new Builder();
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(Level.BASIC);
okHttpBuilder.addInterceptor(loggingInterceptor);
okHttpBuilder.addNetworkInterceptor(loggingInterceptor);
options.callFactory = okHttpBuilder.build();
options.webSocketFactory = okHttpBuilder.build();
}
options.callFactory = okHttpBuilder.build();
options.webSocketFactory = okHttpBuilder.build();
socket = IO.socket(baseURL, options);
URL parsed = new URL(baseURL);
protocol = parsed.getProtocol();
Expand Down Expand Up @@ -325,12 +345,12 @@ public void call(Object... args) {
logger.warn("Error connecting to the openHAB Cloud instance. Reconnecting.");
}
socket.close();
scheduler.schedule(new Runnable() {
reconnectFuture.getAndSet(Optional.of(scheduler.schedule(new Runnable() {
@Override
public void run() {
socket.connect();
}
}, delay, TimeUnit.MILLISECONDS);
}, delay, TimeUnit.MILLISECONDS))).ifPresent(future -> future.cancel(true));
}
})//

Expand Down Expand Up @@ -671,17 +691,10 @@ public boolean isConnected() {
*/
public void shutdown() {
logger.info("Shutting down openHAB Cloud service connection");
reconnectFuture.get().ifPresent(future -> future.cancel(true));
socket.disconnect();
}

public String getOpenHABVersion() {
return openHABVersion;
}

public void setOpenHABVersion(String openHABVersion) {
this.openHABVersion = openHABVersion;
}

public void setListener(CloudClientListener listener) {
this.listener = listener;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,6 @@ protected void modified(Map<String, ?> config) {
String localBaseUrl = "http://localhost:" + localPort;
cloudClient = new CloudClient(httpClient, InstanceUUID.get(), getSecret(), cloudBaseUrl, localBaseUrl,
remoteAccessEnabled, exposedItems);
cloudClient.setOpenHABVersion(OpenHAB.getVersion());
cloudClient.connect();
cloudClient.setListener(this);
NotificationAction.cloudService = this;
Expand Down