Add entity name for jobs

This commit is contained in:
ViacheslavKlimov 2025-05-23 15:20:08 +03:00
parent 2bb6eab0ed
commit 43176d37fc
7 changed files with 64 additions and 8 deletions

View File

@ -15,6 +15,8 @@
*/
package org.thingsboard.server.service.job;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
@ -49,7 +51,6 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -78,9 +79,9 @@ public class DefaultJobManager implements JobManager {
}
@Override
public Future<Job> submitJob(Job job) {
public ListenableFuture<Job> submitJob(Job job) {
log.debug("Submitting job: {}", job);
return executor.submit(() -> jobService.saveJob(job.getTenantId(), job));
return Futures.submit(() -> jobService.saveJob(job.getTenantId(), job), executor);
}
@Override

View File

@ -248,6 +248,8 @@ public class JobManagerTest extends AbstractControllerTest {
assertThat(job.getStatus()).isEqualTo(JobStatus.COMPLETED);
assertThat(job.getResult().getSuccessfulCount()).isEqualTo(tasksCount);
assertThat(job.getResult().getTotalCount()).isEqualTo(tasksCount);
assertThat(job.getEntityId()).isEqualTo(jobEntity.getId());
assertThat(job.getEntityName()).isEqualTo(jobEntity.getName());
}
});

View File

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.entity;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId;
@ -25,7 +26,9 @@ import org.thingsboard.server.common.data.query.EntityCountQuery;
import org.thingsboard.server.common.data.query.EntityData;
import org.thingsboard.server.common.data.query.EntityDataQuery;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
public interface EntityService {
@ -37,6 +40,8 @@ public interface EntityService {
Optional<HasId<?>> fetchEntity(TenantId tenantId, EntityId entityId);
Map<EntityId, EntityInfo> fetchEntityInfos(TenantId tenantId, CustomerId customerId, Set<EntityId> entityIds);
Optional<NameLabelAndCustomerDetails> fetchNameLabelAndCustomerDetails(TenantId tenantId, EntityId entityId);
long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query);

View File

@ -47,6 +47,7 @@ public class Job extends BaseData<JobId> implements HasTenantId {
private String key;
@NotNull
private EntityId entityId;
private String entityName; // read-only
@NotNull
private JobStatus status;
@NotNull

View File

@ -20,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasCustomerId;
import org.thingsboard.server.common.data.HasEmail;
@ -41,19 +42,24 @@ import org.thingsboard.server.common.data.query.EntityDataPageLink;
import org.thingsboard.server.common.data.query.EntityDataQuery;
import org.thingsboard.server.common.data.query.EntityFilterType;
import org.thingsboard.server.common.data.query.EntityKey;
import org.thingsboard.server.common.data.query.EntityKeyType;
import org.thingsboard.server.common.data.query.EntityListFilter;
import org.thingsboard.server.common.data.query.EntityNameFilter;
import org.thingsboard.server.common.data.query.EntityTypeFilter;
import org.thingsboard.server.common.data.query.KeyFilter;
import org.thingsboard.server.common.data.query.RelationsQueryFilter;
import org.thingsboard.server.common.data.query.TsValue;
import org.thingsboard.server.common.msg.edqs.EdqsApiService;
import org.thingsboard.server.common.stats.EdqsStatsService;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@ -199,6 +205,30 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
return fetchAndConvert(tenantId, entityId, Function.identity());
}
@Override
public Map<EntityId, EntityInfo> fetchEntityInfos(TenantId tenantId, CustomerId customerId, Set<EntityId> entityIds) {
Map<EntityId, EntityInfo> infos = new HashMap<>();
entityIds.stream()
.collect(Collectors.groupingBy(EntityId::getEntityType))
.forEach((entityType, ids) -> {
EntityListFilter filter = new EntityListFilter();
filter.setEntityType(entityType);
filter.setEntityList(ids.stream().map(Object::toString).toList());
EntityDataQuery query = new EntityDataQuery(filter, new EntityDataPageLink(ids.size(), 0, null, null),
List.of(new EntityKey(EntityKeyType.ENTITY_FIELD, ModelConstants.NAME_PROPERTY)), Collections.emptyList(), Collections.emptyList());
entityQueryDao.findEntityDataByQuery(tenantId, customerId, query).getData().forEach(entityData -> {
EntityId entityId = entityData.getEntityId();
Optional.ofNullable(entityData.getLatest().get(EntityKeyType.ENTITY_FIELD))
.map(fields -> fields.get(ModelConstants.NAME_PROPERTY))
.map(TsValue::getValue).ifPresent(name -> {
infos.put(entityId, new EntityInfo(entityId, name));
});
});
});
return infos;
}
private <T> Optional<T> fetchAndConvert(TenantId tenantId, EntityId entityId, Function<HasId<?>, T> converter) {
EntityDaoService entityDaoService = entityServiceRegistry.getServiceByEntityType(entityId.getEntityType());
Optional<HasId<?>> entityOpt = entityDaoService.findEntity(tenantId, entityId);
@ -295,7 +325,7 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
}
if ((query.getEntityFields() == null || query.getEntityFields().isEmpty()) &&
(query.getLatestValues() == null || query.getLatestValues().isEmpty())) {
(query.getLatestValues() == null || query.getLatestValues().isEmpty())) {
return false;
}

View File

@ -20,6 +20,7 @@ import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Limit;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.JobId;
@ -32,13 +33,17 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.util.CollectionsUtil;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.dao.job.JobDao;
import org.thingsboard.server.dao.model.sql.JobEntity;
import org.thingsboard.server.dao.sql.JpaAbstractDao;
import org.thingsboard.server.dao.util.SqlDao;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
@Component
@SqlDao
@ -46,16 +51,29 @@ import java.util.UUID;
public class JpaJobDao extends JpaAbstractDao<JobEntity, Job> implements JobDao {
private final JobRepository jobRepository;
private final EntityService entityService;
@Override
public PageData<Job> findByTenantIdAndFilter(TenantId tenantId, JobFilter filter, PageLink pageLink) {
return DaoUtil.toPageData(jobRepository.findByTenantIdAndTypesAndStatusesAndEntitiesAndTimeAndSearchText(tenantId.getId(),
PageData<Job> jobs = DaoUtil.toPageData(jobRepository.findByTenantIdAndTypesAndStatusesAndEntitiesAndTimeAndSearchText(tenantId.getId(),
CollectionsUtil.isEmpty(filter.getTypes()) ? null : filter.getTypes(),
CollectionsUtil.isEmpty(filter.getStatuses()) ? null : filter.getStatuses(),
CollectionsUtil.isEmpty(filter.getEntities()) ? null : filter.getEntities(),
filter.getStartTime() != null ? filter.getStartTime() : 0,
filter.getEndTime() != null ? filter.getEndTime() : 0,
Strings.emptyToNull(pageLink.getTextSearch()), DaoUtil.toPageable(pageLink)));
Set<EntityId> entityIds = jobs.getData().stream()
.map(Job::getEntityId)
.collect(Collectors.toSet());
Map<EntityId, EntityInfo> entityInfos = entityService.fetchEntityInfos(tenantId, null, entityIds);
jobs.getData().forEach(job -> {
EntityInfo entityInfo = entityInfos.get(job.getEntityId());
if (entityInfo != null) {
job.setEntityName(entityInfo.getName());
}
});
return jobs;
}
@Override

View File

@ -15,15 +15,14 @@
*/
package org.thingsboard.rule.engine.api;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.id.JobId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.job.Job;
import java.util.concurrent.Future;
public interface JobManager {
Future<Job> submitJob(Job job); // TODO: rate limits
ListenableFuture<Job> submitJob(Job job); // TODO: rate limits
void cancelJob(TenantId tenantId, JobId jobId);