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] Reconnect on connection errors #11153

Merged
merged 7 commits into from
Nov 12, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions bundles/org.openhab.io.openhabcloud/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@
<dependency>
<groupId>org.openhab.osgiify</groupId>
<artifactId>io.socket.socket.io-client</artifactId>
<version>1.0.0</version>
<version>1.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openhab.osgiify</groupId>
<artifactId>io.socket.engine.io-client</artifactId>
<version>1.0.0</version>
<version>1.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
<bundle dependency="true">mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.jsr305/3.0.2_1</bundle>
<bundle dependency="true">mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.okhttp/3.8.1_1</bundle>
<bundle dependency="true">mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.okio/1.13.0_1</bundle>
<bundle dependency="true">mvn:org.openhab.osgiify/io.socket.socket.io-client/1.0.0</bundle>
<bundle dependency="true">mvn:org.openhab.osgiify/io.socket.engine.io-client/1.0.0</bundle>
<bundle dependency="true">mvn:org.openhab.osgiify/io.socket.socket.io-client/1.0.1</bundle>
<bundle dependency="true">mvn:org.openhab.osgiify/io.socket.engine.io-client/1.0.1</bundle>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.io.openhabcloud/${project.version}</bundle>
</feature>
</features>
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.socket.backo.Backoff;
import io.socket.client.IO;
import io.socket.client.Manager;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
import io.socket.engineio.client.Transport;
import io.socket.thread.EventThread;

/**
* This class provides communication between openHAB and the openHAB Cloud service.
Expand Down Expand Up @@ -122,6 +124,11 @@ public class CloudClient {
private boolean remoteAccessEnabled;
private Set<String> exposedItems;

/**
* Back-off strategy for reconnecting when manual reconnection is needed
*/
private final Backoff reconnectBackoff = new Backoff();

/**
* Constructor of CloudClient
*
Expand All @@ -139,6 +146,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);
}

/**
Expand Down Expand Up @@ -174,6 +184,25 @@ public void call(Object... args) {
}
});
}
}).on(Manager.EVENT_CONNECT_ERROR, new Emitter.Listener() {

@Override
public void call(Object... args) {
if (args.length > 0) {
if (args[0] instanceof Exception) {
Exception e = (Exception) args[0];
logger.debug(
"Error connecting to the openHAB Cloud instance: {} {}. Should reconnect automatically.",
e.getClass().getSimpleName(), e.getMessage());
} else {
logger.debug(
"Error connecting to the openHAB Cloud instance: {}. Should reconnect automatically.",
args[0]);
}
} else {
logger.debug("Error connecting to the openHAB Cloud instance. Should reconnect automatically.");
}
}
});
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
@Override
Expand All @@ -182,20 +211,86 @@ public void call(Object... args) {
isConnected = true;
onConnect();
}
}).on(Socket.EVENT_CONNECTING, new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.debug("Socket.IO connecting");
}
}).on(Socket.EVENT_RECONNECTING, new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.debug("Socket.IO re-connecting (attempt {})", args[0]);
}
}).on(Socket.EVENT_RECONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.debug("Socket.IO re-connected successfully (attempt {})", args[0]);
}
}).on(Socket.EVENT_RECONNECT_ERROR, new Emitter.Listener() {
@Override
public void call(Object... args) {
if (args[0] instanceof Exception) {
Exception e = (Exception) args[0];
logger.debug("Socket.IO re-connect attempt error: {} {}", e.getClass().getSimpleName(),
e.getMessage());
} else {
logger.debug("Socket.IO re-connect attempt error: {}", args[0]);
}
}
}).on(Socket.EVENT_RECONNECT_FAILED, new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.debug("Socket.IO re-connect attempts failed. Stopping reconnection.");
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
logger.debug("Socket.IO disconnected");
if (args.length > 0) {
logger.debug("Socket.IO disconnected: {}", args[0]);
} else {
logger.debug("Socket.IO disconnected");
}
isConnected = false;
onDisconnect();
}
}).on(Socket.EVENT_ERROR, new Emitter.Listener() {
@Override
public void call(Object... args) {
if (logger.isDebugEnabled()) {
logger.error("Error connecting to the openHAB Cloud instance: {}", args[0]);
if (CloudClient.this.socket.connected()) {
if (logger.isDebugEnabled() && args.length > 0) {
logger.error("Error during communication: {}", args[0]);
} else {
logger.error("Error during communication");
}
} else {
logger.error("Error connecting to the openHAB Cloud instance");
// We are not connected currently, manual reconnection is needed to keep trying to (re-)establish
// connection.
//
// Socket.IO 1.x java client: 'error' event is emitted from Socket on connection errors that are not
// retried, but also with error that are automatically retried. If we
//
// Note how this is different in Socket.IO 2.x java client, Socket emits 'connect_error' event.
// OBS: Don't get confused with Socket IO 2.x docs online, in 1.x connect_error is emitted also on
// errors that are retried by the library automatically!
long delay = reconnectBackoff.duration();
// Try reconnecting on connection errors
if (logger.isDebugEnabled() && args.length > 0) {
if (args[0] instanceof Exception) {
Exception e = (Exception) args[0];
logger.error(
"Error connecting to the openHAB Cloud instance: {} {}. Reconnecting after {} ms.",
e.getClass().getSimpleName(), e.getMessage(), delay);
} else {
logger.error(
"Error connecting to the openHAB Cloud instance: {}. Reconnecting after {} ms.",
args[0], delay);
}
} else {
logger.error("Error connecting to the openHAB Cloud instance. Reconnecting.");
}
socket.close();
sleepSocketIO(delay);
socket.connect();
}
}
}).on("request", new Emitter.Listener() {
Expand Down Expand Up @@ -224,6 +319,7 @@ public void call(Object... args) {

public void onConnect() {
logger.info("Connected to the openHAB Cloud service (UUID = {}, base URL = {})", this.uuid, this.localBaseUrl);
reconnectBackoff.reset();
isConnected = true;
}

Expand Down Expand Up @@ -578,4 +674,14 @@ private JSONObject getJSONHeaders(HttpFields httpFields) {
}
return headersJSON;
}

private void sleepSocketIO(long delay) {
EventThread.exec(() -> {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {

}
});
}
}