[froniuswattpilot] Fix disposal and increase thread-safety of reconnectJob scheduling (#20711)

* [froniuswattpilot] Fix concurrency bugs & disposal

Signed-off-by: Florian Hotze <dev@florianhotze.com>
This commit is contained in:
Florian Hotze
2026-05-20 20:32:01 +02:00
committed by GitHub
parent 743542526c
commit ca2f271da8
@@ -68,6 +68,7 @@ public class FroniusWattpilotHandler extends BaseThingHandler implements Wattpil
private @Nullable FroniusWattpilotConfiguration config;
private @Nullable ScheduledFuture<?> reconnectJob;
private volatile boolean isDisposed = false;
public FroniusWattpilotHandler(Thing thing, HttpClient httpClient) {
super(thing);
@@ -200,6 +201,10 @@ public class FroniusWattpilotHandler extends BaseThingHandler implements Wattpil
@Override
public void initialize() {
if (isDisposed) {
logger.debug("Skipping initialization because handler is already disposed.");
return;
}
config = getConfigAs(FroniusWattpilotConfiguration.class);
FroniusWattpilotConfiguration config = this.config;
@@ -231,21 +236,37 @@ public class FroniusWattpilotHandler extends BaseThingHandler implements Wattpil
@Override
public void dispose() {
try {
client.disconnect().get(3, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
logger.error("Failed to disconnect", e);
isDisposed = true;
synchronized (this) {
var reconnectJob = this.reconnectJob;
if (reconnectJob != null) {
reconnectJob.cancel(false);
this.reconnectJob = null;
}
}
client.removeListener(this);
try {
client.disconnect().get(3, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.error("Failed to disconnect", e);
} catch (ExecutionException | TimeoutException e) {
logger.error("Failed to disconnect", e);
}
}
@Override
public void connected(WattpilotInfo info) {
if (isDisposed) {
return;
}
logger.debug("Connected to Wattpilot.");
var reconnectJob = this.reconnectJob;
if (reconnectJob != null) {
reconnectJob.cancel(false);
this.reconnectJob = null;
synchronized (this) {
var reconnectJob = this.reconnectJob;
if (reconnectJob != null) {
reconnectJob.cancel(false);
this.reconnectJob = null;
}
}
updateStatus(ThingStatus.ONLINE);
updateDeviceProperties(info);
@@ -253,17 +274,25 @@ public class FroniusWattpilotHandler extends BaseThingHandler implements Wattpil
@Override
public void disconnected(String reason, @Nullable Throwable cause) {
if (isDisposed) {
return;
}
logger.debug("Disconnected from Wattpilot: {}", reason, cause);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, reason);
var reconnectJob = this.reconnectJob;
if (cause != null && reconnectJob == null) {
logger.debug("Connection to Wattpilot lost, scheduling reconnection job ...", cause);
this.reconnectJob = scheduler.scheduleAtFixedRate(this::initialize, 30L, 60L, TimeUnit.SECONDS);
synchronized (this) {
var reconnectJob = this.reconnectJob;
if (cause != null && reconnectJob == null && !isDisposed) {
logger.debug("Connection to Wattpilot lost, scheduling reconnection job ...", cause);
this.reconnectJob = scheduler.scheduleAtFixedRate(this::initialize, 30L, 60L, TimeUnit.SECONDS);
}
}
}
@Override
public void statusChanged(WattpilotStatus status) {
if (isDisposed) {
return;
}
updateChannelsControl(status);
updateChannelsStatus(status);
updateChannelsMetrics(status);