[remoteopenhab] New setting to restart the SSE connection after inact… (#10063)

* [remoteopenhab] New setting to restart the SSE connection after inactivity

Fix #9680

Signed-off-by: Laurent Garnier <lg.hc@free.fr>

* Review comments: doc

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
lolodomo 2021-02-06 17:12:22 +01:00 committed by GitHub
parent 3e7ecbf79c
commit 5141781fe7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 12 deletions

View File

@ -45,7 +45,8 @@ The `server` thing has the following configuration parameters:
| restPath | yes | The subpath of the REST API on the remote openHAB server. Default is /rest |
| token | no | The token to use when the remote openHAB server is setup to require authorization to run its REST API. |
| accessibilityInterval | no | Minutes between checking the remote server accessibility. 0 to disable the check. Default is 3. |
| aliveInterval | no | Number of last minutes to take into account to determine whether the remote server is alive. 0 to disable this feature. Default is 5. |
| aliveInterval | no | Number of last minutes to consider when monitoring the receipt of events from the remote server. If an event is received during this interval, the remote server is considered alive and its accessibility will not be verified. Use 0 to disable this feature. Default is 5. |
| restartIfNoActivity | no | Set it to true if you want to restart the connection (SSE) to the remote server when no events are received in the monitored interval. It is not necessary if the goal is to properly handle a short network outage (few seconds). This can be useful if you want to deal with a long network outage. Do not enable it if you remote server does not send events during the monitored interval under normal conditions, it will cause frequent restart of the connection and potential loss of events. Default is false. |
The `thing` thing has the following configuration parameters:

View File

@ -35,4 +35,5 @@ public class RemoteopenhabServerConfiguration {
public String token = "";
public int accessibilityInterval = 3;
public int aliveInterval = 5;
public boolean restartIfNoActivity = false;
}

View File

@ -174,9 +174,9 @@ public class RemoteopenhabBridgeHandler extends BaseBridgeHandler
updateStatus(ThingStatus.UNKNOWN);
scheduler.submit(this::checkConnection);
scheduler.submit(() -> checkConnection(false));
if (config.accessibilityInterval > 0) {
startCheckConnectionJob(config.accessibilityInterval, config.aliveInterval);
startCheckConnectionJob(config.accessibilityInterval, config.aliveInterval, config.restartIfNoActivity);
}
}
@ -343,7 +343,7 @@ public class RemoteopenhabBridgeHandler extends BaseBridgeHandler
}
}
public void checkConnection() {
public void checkConnection(boolean restartSse) {
logger.debug("Try the root REST API...");
try {
restClient.tryApi();
@ -367,6 +367,9 @@ public class RemoteopenhabBridgeHandler extends BaseBridgeHandler
"Dynamic creation of the channels for the remote server items failed");
stopStreamingUpdates();
}
} else if (restartSse) {
logger.debug("The SSE connection is restarted because there was no recent event received");
restartStreamingUpdates();
}
} catch (RemoteopenhabException e) {
logger.debug("{}", e.getMessage());
@ -375,7 +378,7 @@ public class RemoteopenhabBridgeHandler extends BaseBridgeHandler
}
}
private void startCheckConnectionJob(int accessibilityInterval, int aliveInterval) {
private void startCheckConnectionJob(int accessibilityInterval, int aliveInterval, boolean restartIfNoActivity) {
ScheduledFuture<?> localCheckConnectionJob = checkConnectionJob;
if (localCheckConnectionJob == null || localCheckConnectionJob.isCancelled()) {
checkConnectionJob = scheduler.scheduleWithFixedDelay(() -> {
@ -383,12 +386,12 @@ public class RemoteopenhabBridgeHandler extends BaseBridgeHandler
if (getThing().getStatus() != ThingStatus.ONLINE || aliveInterval == 0
|| restClient.getLastEventTimestamp() == 0) {
logger.debug("Time to check server accessibility");
checkConnection();
checkConnection(restartIfNoActivity && aliveInterval != 0);
} else if (millisSinceLastEvent > (aliveInterval * 60000)) {
logger.debug(
"Time to check server accessibility (maybe disconnected from streaming events, millisSinceLastEvent={})",
millisSinceLastEvent);
checkConnection();
checkConnection(restartIfNoActivity);
} else {
logger.debug(
"Bypass server accessibility check (receiving streaming events, millisSinceLastEvent={})",

View File

@ -13,6 +13,7 @@
package org.openhab.binding.remoteopenhab.internal.rest;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
@ -21,6 +22,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
@ -182,7 +184,7 @@ public class RemoteopenhabRestClient {
public void sendCommandToRemoteItem(String itemName, Command command) throws RemoteopenhabException {
try {
String url = String.format("%s/%s", getRestApiUrl("items"), itemName);
executeUrl(HttpMethod.POST, url, "application/json", command.toFullString(), "text/plain", false);
executeUrl(HttpMethod.POST, url, "application/json", command.toFullString(), "text/plain", false, true);
} catch (RemoteopenhabException e) {
throw new RemoteopenhabException("Failed to send command to the remote item " + itemName
+ " using the items REST API: " + e.getMessage(), e);
@ -470,11 +472,11 @@ public class RemoteopenhabRestClient {
}
public String executeGetUrl(String url, String acceptHeader, boolean asyncReading) throws RemoteopenhabException {
return executeUrl(HttpMethod.GET, url, acceptHeader, null, null, asyncReading);
return executeUrl(HttpMethod.GET, url, acceptHeader, null, null, asyncReading, true);
}
public String executeUrl(HttpMethod httpMethod, String url, String acceptHeader, @Nullable String content,
@Nullable String contentType, boolean asyncReading) throws RemoteopenhabException {
@Nullable String contentType, boolean asyncReading, boolean retryIfEOF) throws RemoteopenhabException {
final Request request = httpClient.newRequest(url).method(httpMethod).timeout(REQUEST_TIMEOUT,
TimeUnit.MILLISECONDS);
@ -517,6 +519,16 @@ public class RemoteopenhabRestClient {
}
} catch (RemoteopenhabException e) {
throw e;
} catch (ExecutionException e) {
// After a long network outage, the first HTTP request will fail with an EOFException exception.
// We retry the request a second time in this case.
Throwable cause = e.getCause();
if (retryIfEOF && cause instanceof EOFException) {
logger.debug("EOFException - retry the request");
return executeUrl(httpMethod, url, acceptHeader, content, contentType, asyncReading, false);
} else {
throw new RemoteopenhabException(e);
}
} catch (Exception e) {
throw new RemoteopenhabException(e);
}

View File

@ -63,11 +63,24 @@
<parameter name="aliveInterval" type="integer" min="0" step="1" unit="min">
<label>Alive Interval</label>
<description>Number of last minutes to take into account to determine whether the remote server is alive. 0 to
disable this feature. Default is 5.</description>
<description>Number of last minutes to consider when monitoring the receipt of events from the remote server. If an
event is received during this interval, the remote server is considered alive and its accessibility will not be
verified. Use 0 to disable this feature. Default is 5.</description>
<default>5</default>
<advanced>true</advanced>
</parameter>
<parameter name="restartIfNoActivity" type="boolean">
<label>Restart if no Activity</label>
<description>Set it to true if you want to restart the connection (SSE) to the remote server when no events are
received in the monitored interval. It is not necessary if the goal is to properly handle a short network outage
(few seconds). This can be useful if you want to deal with a long network outage. Do not enable it if you remote
server does not send events during the monitored interval under normal conditions, it will cause frequent restart
of the connection and potential loss of events. Default is false.
</description>
<default>false</default>
<advanced>true</advanced>
</parameter>
</config-description>
</bridge-type>