Creates missing system images from application/src/main/data/resources/images
during LTS patch startup, mirroring the upgrade-path loadSystemResources logic.
Existing system images in the DB are left untouched.
Several testSaveProtoDeviceProfileWithInvalidRpcRequestSchema* tests
intermittently fail with:
org.thingsboard.server.dao.exception.TenantNotFoundException: Tenant
with id <fresh-tenant-uuid> not found
when the tenant created in @Before has not yet been populated in the
tenant profile cache by the time the request hits the partition-lookup
path (DefaultTenantRoutingInfoService -> TbTenantProfileCache ->
TenantService#findTenantById). The underlying request is idempotent
(the schema is invalid so it is rejected with 400 regardless of
retries), so wrap the doPost + status assertion in Awaitility with
Mockito.reset inside the retry block: only the last attempt's
invocations are visible to the subsequent verify* assertions.
Applies to all testSaveDeviceProfileWithInvalidRpcRequestProtoSchema
callers, including the currently-muted
testSaveProtoDeviceProfileWithInvalidRpcRequestSchemaRequestIdDateType.
The test asserts exactly 2 UserCredentialsUpdateMsg after creating a new
tenant-admin user, but the user activation flow can emit either 2 or 3
depending on timing:
- activateUserCredentials publishes CREDENTIALS_UPDATED (msg #1)
- setUserCredentialsEnabled publishes CREDENTIALS_UPDATED (msg #2)
- the initial USER ADDED edge event is processed asynchronously in
UserEdgeProcessor and bundles an extra UserCredentialsUpdateMsg when
it finds userCredentials.isEnabled() == true (i.e. activation
already raced past the ADDED event)
When the race goes the second way we end up with 1 UserUpdateMsg plus
3 UserCredentialsUpdateMsg, which currently fails the hard-coded
assertEquals(2, ...) assertion.
Accept both 2 and 3 UserCredentialsUpdateMsg instead of asserting an
exact count, matching the reality of the asynchronous edge event
pipeline.
Await cached resource data to become available after save eviction
before asserting, and await null after deletion. Prevents Mockito
verifyNoMoreInteractions(resourceService) failure caused by racing
background cache-load invocations.
Backport of 99334ba7fe from master.
- Mark force-added entity-field filter mappings as ignored under OR so
EntityDataAdapter keeps the response shape identical to AND (applied
to both findEntityDataByQuery and validateEntityCountQuery paths).
- Skip the ON-clause filter in toLatestJoin when forceLeftJoin=true to
avoid duplicating the predicate that buildQuery already emits at the
middle layer under OR (different bound parameter names, same filter).
- Document the empty-predicate drop in buildQuery (safe under AND,
narrowing under OR) and the defensive vacuously-true return in
RepositoryUtils.checkKeyFilters.
- Explain why validateEntityCountQuery uses the nullable
getKeyFiltersOperation() rather than the OrDefault helper.
- Add regression test asserting latest[ENTITY_FIELD] under OR only
contains keys declared in entityFields.
- EntityKeyMapping: replace fragile null-swap of entityKeyColumn with a useAliasAsField flag threaded through buildKeyQuery/buildPredicateQuery, avoiding mutation of shared instance state
- TbAlarmCountSubCtx, TbAlarmDataSubCtx: normalize keyFiltersOperation at query construction via getKeyFiltersOperationOrDefault(), matching DefaultEntityQueryService
- BaseEntityService: end the disabled-OR validation error with a period and attribute it to the system administrator, aligning with the existing UI translation
- EntityQueryControllerTest: extract helpers (createDeviceWithSharedAttributes, createDeviceWithTimeseries, createAlarm, deviceTypeFilter, numericKeyFilter, stringKeyFilter, pageLinkSortedByName, nameEntityField, extractNames) and replace the pagination test's obscure temperature ternary with an explicit array
Relax version check to allow maintenance digit increases within the same
LTS family (e.g. 4.3.0 -> 4.3.1), not just patch digit increases.
Add LTS SQL schema patch execution from upgrade/lts/schema_update.sql,
running before views and widget updates so schema changes are in place
for dependent objects.
Replace the blocking semaphore guard with a non-blocking bounded FIFO queue
+ semaphore pattern:
- No semaphore/queue when maxParallelRequestsCount=0 (default): direct doHttpCall,
identical to the old behavior.
- When a concurrency limit is set, incoming messages are enqueued via non-blocking
offer(); a full queue triggers onFailure immediately.
- tryProcess() acquires one semaphore slot and dispatches the next valid queued task.
Stale tasks (batch deadline expired) are dropped and the slot reused in the same pass.
- doFinally hook releases the semaphore and calls tryProcess() exactly once after any
terminal signal (success, error, cancel), preventing double-release and permit leaks.
- publishOn(externalCallExecutor) moves callbacks off reactor-netty I/O threads.
System-level safety caps are wired through thingsboard.yml → ActorSystemContext →
TbContext → TbHttpClient, scoped to rule-engine services only via @TbRuleEngineComponent:
actors.rule.external.http_client.max_parallel_requests (ACTORS_RULE_EXTERNAL_HTTP_CLIENT_MAX_PARALLEL_REQUESTS)
actors.rule.external.http_client.max_pending_requests (ACTORS_RULE_EXTERNAL_HTTP_CLIENT_MAX_PENDING_REQUESTS)
actors.rule.external.http_client.pool_max_connections (ACTORS_RULE_EXTERNAL_HTTP_CLIENT_POOL_MAX_CONNECTIONS)
Backward compat: TB_RE_HTTP_CLIENT_POOL_MAX_CONNECTIONS still honored via yaml fallback.
Observability: five AtomicLong counters (dispatched, success, failure, droppedQueueFull,
droppedStale) with periodic WARN anomaly logging including semaphorePermits for leak detection.
No configuration changes or upgrade scripts required — docker image update is sufficient.
Rename RestApiCallNodeSettings to TbHttpClientSettings
The settings are about HTTP client transport concerns (connection pool,
concurrency, queue depth), not REST API Call node business logic.
The new name matches the consumer (TbHttpClient) and the YAML path
(actors.rule.external.http_client.*).
Field-level @JsonIgnoreProperties is a serialization concern that should
not pollute global OpenAPI schemas. Strip it in mapAwareConverter before
ModelResolver sees it. Remove CalculatedField pre-registration as it
loses descriptions on $ref properties.
Pre-registering abstract intermediate types pulls in their full
inheritance chain (UUIDBased, HasUUID) as broken $ref entries.
Leave *Object schemas for these types as-is.
- Remove *Object duplicate schemas when base schema exists
- Pre-register CalculatedField, ContactBased, HasId to prevent
resolution-order issues with @JsonIgnoreProperties
- Deduplicate identical inline allOf entries
- Replace oneOf in additionalProperties.items with base type $ref
Springdoc creates duplicate schemas with an "Object" suffix when a
discriminated type is resolved through multiple paths. Remove identical
duplicates and replace inline oneOf in additionalProperties.items with
base type $ref for Map<K, List<PolymorphicType>> fields.
- Restore private on TEST_SCRIPT_EXPRESSION in CalculatedFieldController
- Restore @Valid on deprecated alarms field in DeviceProfileData
- Remove broken type guard in getTestScriptDialog (AlarmRuleDefinition
DTO has no type field, causing the dialog to never open)
Move test script execution logic from controllers to TbCalculatedFieldService,
eliminating the dependency of AlarmRuleController on CalculatedFieldController.
Simplify entity type filtering in getAlarmRules. Add AlarmRuleControllerTest
covering all endpoints.
Remove <pkg.skip.bootjar>false</pkg.skip.bootjar> from all child
module <properties> blocks. The root POM already defaults it to false,
and child declarations block the skip-pkg profile override, so
-Dpkg.skip=true was never actually skipping spring-boot:repackage.
Also remove the unused surefire.version property (superseded by
maven-surefire-plugin.version).