- Extract the tenant-profile fetch lock stripe count to a named constant (PR #15744)
- Trim the stale global-lock sentence from the per-tenant lock comment (PR #15744)
- Rename the rate-limit onCreate callback to onMiss and document its idempotency requirement (PR #15744)
- Reuse a single tenant profile local in update(TenantProfileUpdateResult) (PR #15744)
- Make the transport callback thread pool size configurable via transport.callback_thread_pool_size (PR #15744)
- Add a parameterized test locking the TransportLimitsType enum-to-profile-field mapping (PR #15744)
- Add device/gateway rate-limit coverage asserting update(tenantId) reaches tracked entities (PR #15744)
- Add a same-tenant fetch-dedup test and pin the cross-tenant test to distinct stripes (PR #15744)
Construct CoapServer and the LwM2M bootstrap server inside the init try block so a failure in the constructor or build() is cleaned up by the existing catch. Guard CoAP shutdown() against a null server. Add a DTLS-enabled CoAP test that covers the dtlsSessionsExecutor shutdown branch.
The defective code lives in common/transport/transport-api and is shared by all
transports (MQTT, HTTP, CoAP, LwM2M, SNMP); the production incident happened to
surface on MQTT.
On a cold tenant-profile cache (e.g. after a cache clear + restart), a device
reconnect storm could serialize the whole transport instance behind tenant-profile
resolution, saturating the callback pool and stalling the node for ~15 minutes.
Two compounding causes are addressed:
- DefaultTransportTenantProfileCache held a single process-wide ReentrantLock across
the synchronous cross-service getEntityProfile round-trip, so every tenant-profile
cache miss in the whole process was serialized one-at-a-time. Replace it with a
bounded set of per-tenant locks (Guava Striped) so different tenants resolve
concurrently while concurrent misses for the same tenant are still de-duplicated.
- DefaultTransportRateLimitService performed that blocking fetch inside
ConcurrentHashMap.computeIfAbsent's mapping function, holding a CHM bin lock across
the remote round-trip. Pre-fetch the tenant profile before computeIfAbsent so no bin
lock is held across I/O.
Also de-duplicate the four near-identical getXRateLimits methods into one generic
helper, move the per-type rate-limit getters onto the TransportLimitsType enum, and
avoid fetching the tenant profile four times in update(TenantId).
Bump LangChain4j to 1.16.1-TB1, which adds frequencyPenalty and
presencePenalty support to the langchain4j-google-genai integration,
and pass both parameters through for Google Gemini and Google Vertex AI
Gemini models.
Collapse maybeOpenDeepLinkedItem into a single openItemDetail call.
Devices resolve via getInstalledItemCounts and pass only the
{ count } for the deep-linked itemId; every other type resolves via
resolveInstalledItem and passes only the matching { installed }
entity (no more synthetic 0/1 count for non-device types).
Bring the same fetch-failure UI to every IoT Hub surface (browse,
search, home, creator profile) so all of them recover gracefully
from network / server outages instead of dead-ending on a global
error toast or a hard redirect.
- Add a tb-no-service-bg global utility in form.scss that mirrors
tb-no-data-bg but renders /assets/home/no-service.svg (copied
from thingsboard.io). Same primary-color mask treatment, so PE
builds retint without re-exporting the asset.
- Add hasError / retryTimer state to the four affected components
and switch their data calls to ignoreErrors: true so the global
toast no longer fires. hasError flips to true on error, stays
true while retries are pending, and is only cleared in the
`next` callback of the next request that actually succeeds.
- Add retryLoad* helpers (retryLoadItems / retryLoadResults /
retryLoadPopularItems / retryLoadCreator) that set isLoading=true
immediately and schedule the real load via a 350ms setTimeout so
rapid-fire retry clicks coalesce into one network round-trip.
- Search component drops the inline switchMap-on-searchSubject path
and pipes the debounced subject straight into loadResults() so
search-triggered loads go through the same error / spinner /
retry plumbing.
- Render the error block consistently across surfaces: in browse
and search inside their respective results container, on the
home page right after the category cards, on the creator profile
as the whole page body (replacing the old router.navigate to
/iot-hub). Each block uses .tb-no-service-bg + the new
iot-hub.network-server-unavailable / -text / try-again locale
keys and binds the primary button to the matching retryLoad*
method.
- Add the matching .tb-iot-hub-empty-state typography (18/500
title, 14/0.54 body, 24px button gap) to the home and creator
profile SCSS so the wrapper matches the layout already used in
browse / search.
Also pick up an unrelated dashboard-widget-select adjustment touched
in the same workspace.
- Drop the DEVICE-only `tb-iot-hub-card-preview-device` /
`dlg-preview-device` variants in the item card and item detail
dialog. The previously-special white-background-with-border treatment
is gone — device previews now reuse the same dot-pattern background
as widgets / solution templates for a consistent look.
- In the home-page iot-hub widget, fold the
`tb-iot-hub-widget-card-image-pattern` modifier into the base
`.tb-iot-hub-widget-card-image` so every preview card already paints
the dot pattern (no opt-in class required).
- Rename `.tb-search-categories` to `.tb-results-container` across
the iot-hub-search component / search page / creator profile pages
so the wrapper class better reflects what it actually contains
(browse / search results) and stays consistent between the search
component and the screens that embed it.
- Pick up incidental browse / search component html / scss tweaks
touched alongside the rename.
All response format implementations return a non-null LangChain4j ResponseFormat; the annotation was a leftover from an earlier iteration where TEXT mapped to null.
The upgrade changed which versions the dependency tree requests:
- drop threetenbp pin: transitives now converge on 1.6.8 without it
- lower checker-qual to 3.42.0: the highest version any transitive requests
- raise error_prone_annotations to 2.43.0: the old pin silently downgraded
dependencies requesting 2.41.0 and 2.43.0
Upgrade LangChain4j to 1.15.1-TB1 and migrate GitHub Models to the
official OpenAI integration (OpenAiOfficialChatModel), enabling JSON
Schema (strict) structured output for GitHub Models and exposing JSON
Schema as a response format for Anthropic and Amazon Bedrock.
- Rename model capability flags to supportsSchemalessJsonOutput() and
supportsJsonSchemaOutput(), declared explicitly per provider
- Push response-format capability checks into TbResponseFormat and
simplify response-format handling in TbAiNode
- Remove obsolete manual JSON escaping for GitHub Models, which now
double-escaped requests under the official OpenAI SDK
- Drop the now-obsolete opennlp-tools version pin (the upgraded
LangChain4j fork ships opennlp-tools >= 2.5.9)
- Update the AI rule node UI to offer response formats per provider,
refresh available model lists, and migrate toggle options to @if
- Expand configurer tests to verify per-provider model configuration