Save time series strategies: initial BE implementation
This commit is contained in:
commit
6ca45f1962
@ -348,7 +348,8 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
|
||||
.tenantId(entityView.getTenantId())
|
||||
.entityId(entityId)
|
||||
.entries(latestValues)
|
||||
.onlyLatest(true)
|
||||
.saveTimeseries(false)
|
||||
.saveLatest(true)
|
||||
.callback(new FutureCallback<Void>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Void tmp) {
|
||||
|
||||
@ -118,10 +118,10 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer
|
||||
EntityId entityId = request.getEntityId();
|
||||
checkInternalEntity(entityId);
|
||||
boolean sysTenant = TenantId.SYS_TENANT_ID.equals(tenantId) || tenantId == null;
|
||||
if (sysTenant || request.isOnlyLatest() || apiUsageStateService.getApiUsageState(tenantId).isDbStorageEnabled()) {
|
||||
if (sysTenant || !request.isSaveTimeseries() || apiUsageStateService.getApiUsageState(tenantId).isDbStorageEnabled()) {
|
||||
KvUtils.validate(request.getEntries(), valueNoXssValidation);
|
||||
ListenableFuture<Integer> future = saveTimeseriesInternal(request);
|
||||
if (!request.isOnlyLatest()) {
|
||||
if (request.isSaveTimeseries()) {
|
||||
FutureCallback<Integer> callback = getApiUsageCallback(tenantId, request.getCustomerId(), sysTenant, request.getCallback());
|
||||
Futures.addCallback(future, callback, tsCallBackExecutor);
|
||||
}
|
||||
@ -135,17 +135,21 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer
|
||||
TenantId tenantId = request.getTenantId();
|
||||
EntityId entityId = request.getEntityId();
|
||||
ListenableFuture<Integer> saveFuture;
|
||||
if (request.isOnlyLatest()) {
|
||||
saveFuture = Futures.transform(tsService.saveLatest(tenantId, entityId, request.getEntries()), result -> 0, MoreExecutors.directExecutor());
|
||||
} else if (request.isSaveLatest()) {
|
||||
if (request.isSaveTimeseries() && request.isSaveLatest()) {
|
||||
saveFuture = tsService.save(tenantId, entityId, request.getEntries(), request.getTtl());
|
||||
} else {
|
||||
} else if (request.isSaveLatest()) {
|
||||
saveFuture = Futures.transform(tsService.saveLatest(tenantId, entityId, request.getEntries()), result -> 0, MoreExecutors.directExecutor());
|
||||
} else if (request.isSaveTimeseries()) {
|
||||
saveFuture = tsService.saveWithoutLatest(tenantId, entityId, request.getEntries(), request.getTtl());
|
||||
} else {
|
||||
saveFuture = Futures.immediateFuture(0);
|
||||
}
|
||||
|
||||
addMainCallback(saveFuture, request.getCallback());
|
||||
addWsCallback(saveFuture, success -> onTimeSeriesUpdate(tenantId, entityId, request.getEntries()));
|
||||
if (request.isSaveLatest() && !request.isOnlyLatest()) {
|
||||
if (request.isSendWsUpdate()) {
|
||||
addWsCallback(saveFuture, success -> onTimeSeriesUpdate(tenantId, entityId, request.getEntries()));
|
||||
}
|
||||
if (request.isSaveTimeseries() && request.isSaveLatest()) {
|
||||
addEntityViewCallback(tenantId, entityId, request.getEntries());
|
||||
}
|
||||
return saveFuture;
|
||||
@ -232,7 +236,8 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer
|
||||
.tenantId(tenantId)
|
||||
.entityId(entityView.getId())
|
||||
.entries(entityViewLatest)
|
||||
.onlyLatest(true)
|
||||
.saveTimeseries(false)
|
||||
.saveLatest(true)
|
||||
.callback(new FutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Void tmp) {}
|
||||
|
||||
@ -38,8 +38,9 @@ public class TimeseriesSaveRequest {
|
||||
private final EntityId entityId;
|
||||
private final List<TsKvEntry> entries;
|
||||
private final long ttl;
|
||||
private final boolean saveTimeseries;
|
||||
private final boolean saveLatest;
|
||||
private final boolean onlyLatest;
|
||||
private final boolean sendWsUpdate;
|
||||
private final FutureCallback<Void> callback;
|
||||
|
||||
public static Builder builder() {
|
||||
@ -53,9 +54,10 @@ public class TimeseriesSaveRequest {
|
||||
private EntityId entityId;
|
||||
private List<TsKvEntry> entries;
|
||||
private long ttl;
|
||||
private FutureCallback<Void> callback;
|
||||
private boolean saveTimeseries = true;
|
||||
private boolean saveLatest = true;
|
||||
private boolean onlyLatest;
|
||||
private boolean sendWsUpdate = true;
|
||||
private FutureCallback<Void> callback;
|
||||
|
||||
Builder() {}
|
||||
|
||||
@ -92,14 +94,18 @@ public class TimeseriesSaveRequest {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder saveTimeseries(boolean saveTimeseries) {
|
||||
this.saveTimeseries = saveTimeseries;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder saveLatest(boolean saveLatest) {
|
||||
this.saveLatest = saveLatest;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder onlyLatest(boolean onlyLatest) {
|
||||
this.onlyLatest = onlyLatest;
|
||||
this.saveLatest = true;
|
||||
public Builder sendWsUpdate(boolean sendWsUpdate) {
|
||||
this.sendWsUpdate = sendWsUpdate;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -123,7 +129,7 @@ public class TimeseriesSaveRequest {
|
||||
}
|
||||
|
||||
public TimeseriesSaveRequest build() {
|
||||
return new TimeseriesSaveRequest(tenantId, customerId, entityId, entries, ttl, saveLatest, onlyLatest, callback);
|
||||
return new TimeseriesSaveRequest(tenantId, customerId, entityId, entries, ttl, saveTimeseries, saveLatest, sendWsUpdate, callback);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -37,8 +37,14 @@ import org.thingsboard.server.common.msg.TbMsg;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNodeConfiguration.PersistenceSettings;
|
||||
import static org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNodeConfiguration.PersistenceSettings.Advanced;
|
||||
import static org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNodeConfiguration.PersistenceSettings.Deduplicate;
|
||||
import static org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNodeConfiguration.PersistenceSettings.OnEveryMessage;
|
||||
import static org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNodeConfiguration.PersistenceSettings.WebSocketsOnly;
|
||||
import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST;
|
||||
|
||||
@Slf4j
|
||||
@ -68,12 +74,15 @@ public class TbMsgTimeseriesNode implements TbNode {
|
||||
private TbContext ctx;
|
||||
private long tenantProfileDefaultStorageTtl;
|
||||
|
||||
private PersistenceSettings persistenceSettings;
|
||||
|
||||
@Override
|
||||
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
|
||||
this.config = TbNodeUtils.convert(configuration, TbMsgTimeseriesNodeConfiguration.class);
|
||||
this.ctx = ctx;
|
||||
ctx.addTenantProfileListener(this::onTenantProfileUpdate);
|
||||
onTenantProfileUpdate(ctx.getTenantProfile());
|
||||
persistenceSettings = config.getPersistenceSettings();
|
||||
}
|
||||
|
||||
void onTenantProfileUpdate(TenantProfile tenantProfile) {
|
||||
@ -88,6 +97,18 @@ public class TbMsgTimeseriesNode implements TbNode {
|
||||
return;
|
||||
}
|
||||
long ts = computeTs(msg, config.isUseServerTs());
|
||||
|
||||
PersistenceDecision persistenceDecision = makePersistenceDecision(ts, msg.getOriginator().getId());
|
||||
boolean saveTimeseries = persistenceDecision.saveTimeseries();
|
||||
boolean saveLatest = persistenceDecision.saveLatest();
|
||||
boolean sendWsUpdate = persistenceDecision.sendWsUpdate();
|
||||
|
||||
// short-circuit
|
||||
if (!saveTimeseries && !saveLatest && !sendWsUpdate) {
|
||||
ctx.tellSuccess(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
String src = msg.getData();
|
||||
Map<Long, List<KvEntry>> tsKvMap = JsonConverter.convertToTelemetry(JsonParser.parseString(src), ts);
|
||||
if (tsKvMap.isEmpty()) {
|
||||
@ -111,7 +132,9 @@ public class TbMsgTimeseriesNode implements TbNode {
|
||||
.entityId(msg.getOriginator())
|
||||
.entries(tsKvEntryList)
|
||||
.ttl(ttl)
|
||||
.saveLatest(!config.isSkipLatestPersistence())
|
||||
.saveTimeseries(saveTimeseries)
|
||||
.saveLatest(saveLatest)
|
||||
.sendWsUpdate(sendWsUpdate)
|
||||
.callback(new TelemetryNodeCallback(ctx, msg))
|
||||
.build());
|
||||
}
|
||||
@ -120,6 +143,37 @@ public class TbMsgTimeseriesNode implements TbNode {
|
||||
return ignoreMetadataTs ? System.currentTimeMillis() : msg.getMetaDataTs();
|
||||
}
|
||||
|
||||
private record PersistenceDecision(boolean saveTimeseries, boolean saveLatest, boolean sendWsUpdate) {}
|
||||
|
||||
private PersistenceDecision makePersistenceDecision(long ts, UUID originatorUuid) {
|
||||
boolean saveTimeseries;
|
||||
boolean saveLatest;
|
||||
boolean sendWsUpdate;
|
||||
|
||||
if (persistenceSettings instanceof OnEveryMessage) {
|
||||
saveTimeseries = true;
|
||||
saveLatest = true;
|
||||
sendWsUpdate = true;
|
||||
} else if (persistenceSettings instanceof WebSocketsOnly) {
|
||||
saveTimeseries = false;
|
||||
saveLatest = false;
|
||||
sendWsUpdate = true;
|
||||
} else if (persistenceSettings instanceof Deduplicate deduplicate) {
|
||||
boolean isFirstMsgInInterval = deduplicate.getDeduplicateStrategy().shouldPersist(ts, originatorUuid);
|
||||
saveTimeseries = isFirstMsgInInterval;
|
||||
saveLatest = isFirstMsgInInterval;
|
||||
sendWsUpdate = isFirstMsgInInterval;
|
||||
} else if (persistenceSettings instanceof Advanced advanced) {
|
||||
saveTimeseries = advanced.timeseries().shouldPersist(ts, originatorUuid);
|
||||
saveLatest = advanced.latest().shouldPersist(ts, originatorUuid);
|
||||
sendWsUpdate = advanced.webSockets().shouldPersist(ts, originatorUuid);
|
||||
} else { // should not happen
|
||||
throw new IllegalArgumentException("Unknown persistence settings type: " + persistenceSettings.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
return new PersistenceDecision(saveTimeseries, saveLatest, sendWsUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
ctx.removeListeners();
|
||||
|
||||
@ -15,22 +15,77 @@
|
||||
*/
|
||||
package org.thingsboard.rule.engine.telemetry;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
||||
import org.thingsboard.rule.engine.telemetry.strategy.PersistenceStrategy;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNodeConfiguration.PersistenceSettings.Advanced;
|
||||
import static org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNodeConfiguration.PersistenceSettings.Deduplicate;
|
||||
import static org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNodeConfiguration.PersistenceSettings.OnEveryMessage;
|
||||
import static org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNodeConfiguration.PersistenceSettings.WebSocketsOnly;
|
||||
|
||||
@Data
|
||||
public class TbMsgTimeseriesNodeConfiguration implements NodeConfiguration<TbMsgTimeseriesNodeConfiguration> {
|
||||
|
||||
private long defaultTTL;
|
||||
private boolean skipLatestPersistence;
|
||||
private boolean useServerTs;
|
||||
private PersistenceSettings persistenceSettings;
|
||||
|
||||
@Override
|
||||
public TbMsgTimeseriesNodeConfiguration defaultConfiguration() {
|
||||
TbMsgTimeseriesNodeConfiguration configuration = new TbMsgTimeseriesNodeConfiguration();
|
||||
configuration.setDefaultTTL(0L);
|
||||
configuration.setSkipLatestPersistence(false);
|
||||
configuration.setUseServerTs(false);
|
||||
configuration.setPersistenceSettings(new OnEveryMessage());
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
include = JsonTypeInfo.As.PROPERTY,
|
||||
property = "type"
|
||||
)
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = OnEveryMessage.class, name = "ON_EVERY_MESSAGE"),
|
||||
@JsonSubTypes.Type(value = WebSocketsOnly.class, name = "WEBSOCKETS_ONLY"),
|
||||
@JsonSubTypes.Type(value = Deduplicate.class, name = "DEDUPLICATE"),
|
||||
@JsonSubTypes.Type(value = Advanced.class, name = "ADVANCED")
|
||||
})
|
||||
sealed interface PersistenceSettings permits OnEveryMessage, Deduplicate, WebSocketsOnly, Advanced {
|
||||
|
||||
record OnEveryMessage() implements PersistenceSettings {}
|
||||
|
||||
record WebSocketsOnly() implements PersistenceSettings {}
|
||||
|
||||
@Getter
|
||||
final class Deduplicate implements PersistenceSettings {
|
||||
|
||||
public final PersistenceStrategy deduplicateStrategy;
|
||||
|
||||
@JsonCreator
|
||||
private Deduplicate(@JsonProperty("deduplicationIntervalSecs") int deduplicationIntervalSecs) {
|
||||
this.deduplicateStrategy = PersistenceStrategy.deduplicate(deduplicationIntervalSecs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
record Advanced(PersistenceStrategy timeseries, PersistenceStrategy latest, PersistenceStrategy webSockets) implements PersistenceSettings {
|
||||
|
||||
public Advanced {
|
||||
Objects.requireNonNull(timeseries);
|
||||
Objects.requireNonNull(latest);
|
||||
Objects.requireNonNull(webSockets);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright © 2016-2024 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.rule.engine.telemetry.strategy;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
final class DeduplicatePersistenceStrategy implements PersistenceStrategy {
|
||||
|
||||
private static final int MIN_DEDUPLICATION_INTERVAL_SECS = 1;
|
||||
|
||||
private final long deduplicationIntervalMillis;
|
||||
private final LoadingCache<Long, Set<UUID>> deduplicationCache;
|
||||
|
||||
@JsonCreator
|
||||
public DeduplicatePersistenceStrategy(@JsonProperty("deduplicationIntervalSecs") int deduplicationIntervalSecs) {
|
||||
if (deduplicationIntervalSecs < MIN_DEDUPLICATION_INTERVAL_SECS) {
|
||||
throw new IllegalArgumentException("Deduplication interval must be at least " + MIN_DEDUPLICATION_INTERVAL_SECS + " second(s), was " + deduplicationIntervalSecs + " second(s)");
|
||||
}
|
||||
deduplicationIntervalMillis = Duration.ofSeconds(deduplicationIntervalSecs).toMillis();
|
||||
deduplicationCache = Caffeine.newBuilder()
|
||||
.softValues()
|
||||
.expireAfterAccess(Duration.ofSeconds(deduplicationIntervalSecs * 10L))
|
||||
.maximumSize(20L)
|
||||
.build(__ -> Sets.newConcurrentHashSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldPersist(long ts, UUID originatorUuid) {
|
||||
long intervalNumber = ts / deduplicationIntervalMillis;
|
||||
return deduplicationCache.get(intervalNumber).add(originatorUuid);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright © 2016-2024 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.rule.engine.telemetry.strategy;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
final class OnEveryMessagePersistenceStrategy implements PersistenceStrategy {
|
||||
|
||||
private static final OnEveryMessagePersistenceStrategy INSTANCE = new OnEveryMessagePersistenceStrategy();
|
||||
|
||||
private OnEveryMessagePersistenceStrategy() {}
|
||||
|
||||
@JsonCreator
|
||||
public static OnEveryMessagePersistenceStrategy getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldPersist(long ts, UUID originatorUuid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright © 2016-2024 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.rule.engine.telemetry.strategy;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
include = JsonTypeInfo.As.PROPERTY,
|
||||
property = "type"
|
||||
)
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = OnEveryMessagePersistenceStrategy.class, name = "ON_EVERY_MESSAGE"),
|
||||
@JsonSubTypes.Type(value = DeduplicatePersistenceStrategy.class, name = "DEDUPLICATE"),
|
||||
@JsonSubTypes.Type(value = SkipPersistenceStrategy.class, name = "SKIP")
|
||||
})
|
||||
public sealed interface PersistenceStrategy permits OnEveryMessagePersistenceStrategy, DeduplicatePersistenceStrategy, SkipPersistenceStrategy {
|
||||
|
||||
static PersistenceStrategy onEveryMessage() {
|
||||
return OnEveryMessagePersistenceStrategy.getInstance();
|
||||
}
|
||||
|
||||
static PersistenceStrategy deduplicate(int deduplicationIntervalSecs) {
|
||||
return new DeduplicatePersistenceStrategy(deduplicationIntervalSecs);
|
||||
}
|
||||
|
||||
static PersistenceStrategy skip() {
|
||||
return SkipPersistenceStrategy.getInstance();
|
||||
}
|
||||
|
||||
boolean shouldPersist(long ts, UUID originatorUuid);
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright © 2016-2024 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.rule.engine.telemetry.strategy;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
final class SkipPersistenceStrategy implements PersistenceStrategy {
|
||||
|
||||
private static final SkipPersistenceStrategy INSTANCE = new SkipPersistenceStrategy();
|
||||
|
||||
private SkipPersistenceStrategy() {}
|
||||
|
||||
@JsonCreator
|
||||
public static SkipPersistenceStrategy getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldPersist(long ts, UUID originatorUuid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@ -33,6 +33,7 @@ import org.thingsboard.rule.engine.api.TbContext;
|
||||
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||
import org.thingsboard.rule.engine.api.TimeseriesSaveRequest;
|
||||
import org.thingsboard.rule.engine.telemetry.strategy.PersistenceStrategy;
|
||||
import org.thingsboard.server.common.adaptor.JsonConverter;
|
||||
import org.thingsboard.server.common.data.TenantProfile;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
@ -88,7 +89,7 @@ public class TbMsgTimeseriesNodeTest {
|
||||
@Test
|
||||
public void verifyDefaultConfig() {
|
||||
assertThat(config.getDefaultTTL()).isEqualTo(0L);
|
||||
assertThat(config.isSkipLatestPersistence()).isFalse();
|
||||
assertThat(config.getPersistenceSettings()).isInstanceOf(TbMsgTimeseriesNodeConfiguration.PersistenceSettings.OnEveryMessage.class);
|
||||
assertThat(config.isUseServerTs()).isFalse();
|
||||
}
|
||||
|
||||
@ -162,7 +163,13 @@ public class TbMsgTimeseriesNodeTest {
|
||||
public void givenSkipLatestPersistenceIsTrueAndTtlFromConfig_whenOnMsg_thenSaveTimeseriesUsingTtlFromConfig() throws TbNodeException {
|
||||
long ttlFromConfig = 5L;
|
||||
config.setDefaultTTL(ttlFromConfig);
|
||||
config.setSkipLatestPersistence(true);
|
||||
|
||||
var timeseriesStrategy = PersistenceStrategy.onEveryMessage();
|
||||
var latestStrategy = PersistenceStrategy.skip();
|
||||
var webSockets = PersistenceStrategy.onEveryMessage();
|
||||
var persistenceSettings = new TbMsgTimeseriesNodeConfiguration.PersistenceSettings.Advanced(timeseriesStrategy, latestStrategy, webSockets);
|
||||
config.setPersistenceSettings(persistenceSettings);
|
||||
|
||||
init();
|
||||
|
||||
String data = """
|
||||
@ -197,7 +204,9 @@ public class TbMsgTimeseriesNodeTest {
|
||||
assertThat(request.getEntityId()).isEqualTo(DEVICE_ID);
|
||||
assertThat(request.getEntries()).containsExactlyElementsOf(expectedList);
|
||||
assertThat(request.getTtl()).isEqualTo(ttlFromConfig);
|
||||
assertThat(request.isSaveTimeseries()).isTrue();
|
||||
assertThat(request.isSaveLatest()).isFalse();
|
||||
assertThat(request.isSendWsUpdate()).isTrue();
|
||||
assertThat(request.getCallback()).isInstanceOf(TelemetryNodeCallback.class);
|
||||
}));
|
||||
verify(ctxMock).tellSuccess(msg);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user