@ -24,6 +24,7 @@ import org.thingsboard.server.actors.TbCalculatedFieldEntityActorId;
import org.thingsboard.server.actors.calculatedField.EntityInitCalculatedFieldMsg.StateAction ;
import org.thingsboard.server.actors.service.DefaultActorService ;
import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor ;
import org.thingsboard.server.common.data.Customer ;
import org.thingsboard.server.common.data.DataConstants ;
import org.thingsboard.server.common.data.EntityType ;
import org.thingsboard.server.common.data.ProfileEntityIdInfo ;
@ -36,6 +37,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId ;
import org.thingsboard.server.common.data.id.TenantId ;
import org.thingsboard.server.common.data.page.PageDataIterable ;
import org.thingsboard.server.common.msg.CalculatedFieldStatePartitionRestoreMsg ;
import org.thingsboard.server.common.msg.cf.CalculatedFieldCacheInitMsg ;
import org.thingsboard.server.common.msg.cf.CalculatedFieldEntityLifecycleMsg ;
import org.thingsboard.server.common.msg.cf.CalculatedFieldPartitionChangeMsg ;
@ -44,6 +46,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TbCallback ;
import org.thingsboard.server.dao.asset.AssetService ;
import org.thingsboard.server.dao.cf.CalculatedFieldService ;
import org.thingsboard.server.dao.customer.CustomerService ;
import org.thingsboard.server.dao.device.DeviceService ;
import org.thingsboard.server.queue.settings.TbQueueCalculatedFieldSettings ;
import org.thingsboard.server.service.cf.CalculatedFieldProcessingService ;
@ -63,8 +66,6 @@ import java.util.List;
import java.util.Map ;
import java.util.Set ;
import java.util.concurrent.CopyOnWriteArrayList ;
import java.util.concurrent.ScheduledFuture ;
import java.util.concurrent.TimeUnit ;
import java.util.function.BiConsumer ;
import static org.thingsboard.server.utils.CalculatedFieldUtils.fromProto ;
@ -79,13 +80,13 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
private final Map < EntityId , List < CalculatedFieldCtx > > entityIdCalculatedFields = new HashMap < > ( ) ;
private final Map < EntityId , List < CalculatedFieldLink > > entityIdCalculatedFieldLinks = new HashMap < > ( ) ;
private final Map < EntityId , Set < EntityId > > ownerEntities = new HashMap < > ( ) ;
private ScheduledFuture < ? > cfsReevaluationTask ;
private final CalculatedFieldProcessingService cfExecService ;
private final CalculatedFieldStateService cfStateService ;
private final CalculatedFieldService cfDaoService ;
private final DeviceService deviceService ;
private final AssetService assetService ;
private final CustomerService customerService ;
private final TbAssetProfileCache assetProfileCache ;
private final TbDeviceProfileCache deviceProfileCache ;
private final TenantEntityProfileCache entityProfileCache ;
@ -102,6 +103,7 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
this . cfDaoService = systemContext . getCalculatedFieldService ( ) ;
this . deviceService = systemContext . getDeviceService ( ) ;
this . assetService = systemContext . getAssetService ( ) ;
this . customerService = systemContext . getCustomerService ( ) ;
this . assetProfileCache = systemContext . getAssetProfileCache ( ) ;
this . deviceProfileCache = systemContext . getDeviceProfileCache ( ) ;
this . entityProfileCache = new TenantEntityProfileCache ( ) ;
@ -120,10 +122,6 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
calculatedFields . clear ( ) ;
entityIdCalculatedFields . clear ( ) ;
entityIdCalculatedFieldLinks . clear ( ) ;
if ( cfsReevaluationTask ! = null ) {
cfsReevaluationTask . cancel ( true ) ;
cfsReevaluationTask = null ;
}
ctx . stop ( ctx . getSelf ( ) ) ;
}
@ -131,7 +129,6 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
log . debug ( "[{}] Processing CF actor init message." , msg . getTenantId ( ) . getId ( ) ) ;
initEntitiesCache ( ) ;
initCalculatedFields ( ) ;
scheduleCfsReevaluation ( ) ;
msg . getCallback ( ) . onSuccess ( ) ;
}
@ -140,9 +137,7 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
var ctx = calculatedFields . get ( cfId ) ;
if ( ctx ! = null ) {
if ( msg . getState ( ) ! = null ) {
msg . getState ( ) . init ( ctx ) ;
}
msg . setCtx ( ctx ) ;
log . debug ( "Pushing CF state restore msg to specific actor [{}]" , msg . getId ( ) . entityId ( ) ) ;
getOrCreateActor ( msg . getId ( ) . entityId ( ) ) . tell ( msg ) ;
} else {
@ -150,21 +145,8 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
}
}
private void scheduleCfsReevaluation ( ) {
cfsReevaluationTask = systemContext . getScheduler ( ) . scheduleWithFixedDelay ( ( ) - > {
try {
calculatedFields . values ( ) . forEach ( cf - > {
if ( cf . isRequiresScheduledReevaluation ( ) ) {
applyToTargetCfEntityActors ( cf , TbCallback . EMPTY , ( entityId , callback ) - > {
log . debug ( "[{}][{}] Pushing scheduled CF reevaluate msg" , entityId , cf . getCfId ( ) ) ;
getOrCreateActor ( entityId ) . tell ( new CalculatedFieldReevaluateMsg ( tenantId , cf ) ) ;
} ) ;
}
} ) ;
} catch ( Exception e ) {
log . warn ( "[{}] Failed to trigger CFs reevaluation" , tenantId , e ) ;
}
} , systemContext . getAlarmsReevaluationInterval ( ) , systemContext . getAlarmsReevaluationInterval ( ) , TimeUnit . SECONDS ) ;
public void onStatePartitionRestoreMsg ( CalculatedFieldStatePartitionRestoreMsg msg ) {
ctx . broadcastToChildren ( msg , true ) ;
}
public void onEntityLifecycleMsg ( CalculatedFieldEntityLifecycleMsg msg ) throws CalculatedFieldException {
@ -172,56 +154,29 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
var entityType = msg . getData ( ) . getEntityId ( ) . getEntityType ( ) ;
var event = msg . getData ( ) . getEvent ( ) ;
switch ( entityType ) {
case CALCULATED_FIELD : {
case CALCULATED_FIELD - > {
switch ( event ) {
case CREATED :
onCfCreated ( msg . getData ( ) , msg . getCallback ( ) ) ;
break ;
case UPDATED :
onCfUpdated ( msg . getData ( ) , msg . getCallback ( ) ) ;
break ;
case DELETED :
onCfDeleted ( msg . getData ( ) , msg . getCallback ( ) ) ;
break ;
default :
msg . getCallback ( ) . onSuccess ( ) ;
break ;
case CREATED - > onCfCreated ( msg . getData ( ) , msg . getCallback ( ) ) ;
case UPDATED - > onCfUpdated ( msg . getData ( ) , msg . getCallback ( ) ) ;
case DELETED - > onCfDeleted ( msg . getData ( ) , msg . getCallback ( ) ) ;
default - > msg . getCallback ( ) . onSuccess ( ) ;
}
break ;
}
case DEVICE :
case ASSET : {
case DEVICE , ASSET , CUSTOMER - > {
switch ( event ) {
case CREATED :
onEntityCreated ( msg . getData ( ) , msg . getCallback ( ) ) ;
break ;
case UPDATED :
onEntityUpdated ( msg . getData ( ) , msg . getCallback ( ) ) ;
break ;
case DELETED :
onEntityDeleted ( msg . getData ( ) , msg . getCallback ( ) ) ;
break ;
default :
msg . getCallback ( ) . onSuccess ( ) ;
break ;
case CREATED - > onEntityCreated ( msg . getData ( ) , msg . getCallback ( ) ) ;
case UPDATED - > onEntityUpdated ( msg . getData ( ) , msg . getCallback ( ) ) ;
case DELETED - > onEntityDeleted ( msg . getData ( ) , msg . getCallback ( ) ) ;
default - > msg . getCallback ( ) . onSuccess ( ) ;
}
break ;
}
case DEVICE_PROFILE :
case ASSET_PROFILE : {
case DEVICE_PROFILE , ASSET_PROFILE - > {
switch ( event ) {
case DELETED :
onProfileDeleted ( msg . getData ( ) , msg . getCallback ( ) ) ;
break ;
default :
msg . getCallback ( ) . onSuccess ( ) ;
break ;
case DELETED - > onProfileDeleted ( msg . getData ( ) , msg . getCallback ( ) ) ;
default - > msg . getCallback ( ) . onSuccess ( ) ;
}
break ;
}
default : {
msg . getCallback ( ) . onSuccess ( ) ;
}
default - > msg . getCallback ( ) . onSuccess ( ) ;
}
}
@ -293,7 +248,10 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
}
private void onEntityDeleted ( ComponentLifecycleMsg msg , TbCallback callback ) {
entityProfileCache . removeEntityId ( msg . getEntityId ( ) ) ;
switch ( msg . getEntityId ( ) . getEntityType ( ) ) {
case DEVICE , ASSET - > entityProfileCache . removeEntityId ( msg . getEntityId ( ) ) ;
case CUSTOMER - > ownerEntities . remove ( msg . getEntityId ( ) ) ;
}
ownerEntities . values ( ) . forEach ( entities - > entities . remove ( msg . getEntityId ( ) ) ) ;
if ( isMyPartition ( msg . getEntityId ( ) , callback ) ) {
log . debug ( "Pushing entity lifecycle msg to specific actor [{}]" , msg . getEntityId ( ) ) ;
@ -426,9 +384,9 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
}
// process all cfs related to owner entity
if ( entityId . getEntityType ( ) . isOneOf ( EntityType . TENANT , EntityType . CUSTOMER ) ) {
List < CalculatedFieldEntityCtxId > ownerCFs = filterOwner EntitiesCFs ( msg ) ;
if ( ! owner CFs . isEmpty ( ) ) {
cfExecService . pushMsgToLinks ( msg , owner CFs , callback ) ;
List < CalculatedFieldEntityCtxId > ownedEntitiesCFs = filterOwned EntitiesCFs ( msg ) ;
if ( ! ownedEntities CFs . isEmpty ( ) ) {
cfExecService . pushMsgToLinks ( msg , ownedEntities CFs , callback ) ;
} else {
callback . onSuccess ( ) ;
}
@ -495,8 +453,8 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
return result ;
}
private List < CalculatedFieldEntityCtxId > filterOwner EntitiesCFs ( CalculatedFieldTelemetryMsg msg ) {
Set < EntityId > entities = getOwner Entities ( msg . getEntityId ( ) ) ;
private List < CalculatedFieldEntityCtxId > filterOwned EntitiesCFs ( CalculatedFieldTelemetryMsg msg ) {
Set < EntityId > entities = getOwned Entities ( msg . getEntityId ( ) ) ;
var proto = msg . getProto ( ) ;
List < CalculatedFieldEntityCtxId > result = new ArrayList < > ( ) ;
for ( var entityId : entities ) {
@ -538,7 +496,7 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
return result ;
}
private Set < EntityId > getOwner Entities ( EntityId entityId ) {
private Set < EntityId > getOwned Entities ( EntityId entityId ) {
if ( entityId = = null ) {
return Collections . emptySet ( ) ;
}
@ -649,21 +607,32 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
log . trace ( "Processing device record: {}" , idInfo ) ;
try {
entityProfileCache . add ( idInfo . getProfileId ( ) , idInfo . getEntityId ( ) ) ;
ownerEntities . computeIfAbsent ( idInfo . getOwnerId ( ) , ownerId - > new HashSet < > ( ) ) . add ( idInfo . getEntityId ( ) ) ;
ownerEntities . computeIfAbsent ( idInfo . getOwnerId ( ) , __ - > new HashSet < > ( ) ) . add ( idInfo . getEntityId ( ) ) ;
} catch ( Exception e ) {
log . error ( "Failed to process device record: {}" , idInfo , e ) ;
}
}
PageDataIterable < ProfileEntityIdInfo > assetIdInfos = new PageDataIterable < > ( pageLink - > assetService . findProfileEntityIdInfosByTenantId ( tenantId , pageLink ) , cfSettings . getInitTenantFetchPackSize ( ) ) ;
for ( ProfileEntityIdInfo idInfo : assetIdInfos ) {
log . trace ( "Processing asset record: {}" , idInfo ) ;
try {
entityProfileCache . add ( idInfo . getProfileId ( ) , idInfo . getEntityId ( ) ) ;
ownerEntities . computeIfAbsent ( idInfo . getOwnerId ( ) , ownerId - > new HashSet < > ( ) ) . add ( idInfo . getEntityId ( ) ) ;
ownerEntities . computeIfAbsent ( idInfo . getOwnerId ( ) , __ - > new HashSet < > ( ) ) . add ( idInfo . getEntityId ( ) ) ;
} catch ( Exception e ) {
log . error ( "Failed to process asset record: {}" , idInfo , e ) ;
}
}
PageDataIterable < Customer > customers = new PageDataIterable < > ( pageLink - > customerService . findCustomersByTenantId ( tenantId , pageLink ) , cfSettings . getInitTenantFetchPackSize ( ) ) ;
for ( Customer customer : customers ) {
log . trace ( "Processing customer record: {}" , customer ) ;
try {
ownerEntities . computeIfAbsent ( customer . getTenantId ( ) , __ - > new HashSet < > ( ) ) . add ( customer . getId ( ) ) ;
} catch ( Exception e ) {
log . error ( "Failed to process customer record: {}" , customer , e ) ;
}
}
}
private void updateEntityOwner ( EntityId entityId ) {