PDGGK opened a new pull request, #125:
URL: https://github.com/apache/iotdb-extras/pull/125

   Deploying the module into a real ThingsBoard for the first time surfaced two 
defects the existing tests could not reach. Until now the module had been 
compiled and integration-tested against ThingsBoard's types, but never run 
inside a live instance — the gap recorded as the second layer of the fork 
release notes.
   
   Environment: `thingsboard/tb-node:4.3.1.2` against 
`apache/iotdb:2.0.8-standalone`, module deployed per `USAGE.md`, driven through 
ThingsBoard's own REST API.
   
   ## The attributes selector could never take effect
   
   ThingsBoard gates its timeseries DAOs on `database.ts.type`, so for `ts` and 
`ts_latest` it steps aside by itself. It offers **no equivalent for 
attributes**: `JpaAttributeDao` is an unconditional `@Component` and registers 
on every deployment, at every version.
   
   So `AttributesDaoConflictGuard` always found a competing bean and failed 
startup:
   
   ```
   database.attributes.type=iotdb-table, but a non-IoTDB AttributesDao bean 
'jpaAttributeDao'
   is present; remove it or unset the IoTDB attributes selector
   ```
   
   Its own advice cannot be followed — a `@Component` cannot be un-registered 
from a properties file. The `USAGE.md` "separate, independent opt-in" was 
therefore a startup failure on any stock ThingsBoard.
   
   The guard now **withdraws** the competing definition rather than refusing to 
start. It partitions the `AttributesDao` candidates first and mutates only once 
a replacement of the same type is known to be registered — withdrawing without 
one leaves zero `AttributesDao` beans, which is an outage rather than a 
degraded mode. It runs at `HIGHEST_PRECEDENCE` (the only one of these 
post-processors that mutates), carries the resolved type out of partitioning so 
the WARN cannot NPE after a mutation, and logs what it removed:
   
   ```
   WARN Removed ThingsBoard bean 'jpaAttributeDao'
        (org.thingsboard.server.dao.sql.attributes.JpaAttributeDao) because
        database.attributes.type=iotdb-table selects the IoTDB attributes 
backend; ThingsBoard
        provides no configuration switch for attributes, so the conflicting 
bean is deregistered
        rather than left to conflict.
   ```
   
   Our own DAO bean also had to lose `@ConditionalOnMissingBean(type = 
AttributesDao)`: that condition is evaluated while configuration classes are 
parsed, strictly before the post-processor runs, so on a stock ThingsBoard it 
skipped our bean on every deployment. Exclusivity is now enforced by the guard, 
which is the only place that can enforce it.
   
   ## A runtime dependency was demoted out of the runtime classpath
   
   `iotdb-thrift-commons` was declared at test scope, with a comment describing 
it as "a transitive runtime dependency of iotdb-session" — which is precisely 
what the declaration broke, since a direct declaration wins under Maven's 
nearest-definition rule. It carries `TEndPoint`, which the session pool needs 
at runtime:
   
   ```
   Caused by: java.lang.NoClassDefFoundError: 
org/apache/iotdb/isession/pool/ITableSessionPool
   Caused by: java.lang.ClassNotFoundException: 
org.apache.iotdb.common.rpc.thrift.TEndPoint
   ```
   
   Verified with `dependency:build-classpath -DincludeScope=runtime`: absent 
before, present after. `dependency:analyze` cannot see a reflective/transitive 
runtime use and reports the compile scope as a test-only dependency, so the 
finding is suppressed with its reason rather than silenced by restoring the 
broken scope.
   
   ## Verification
   
   `mvn -P with-thingsboard,iotdb-table-it verify` — **194 unit tests + 58 
integration tests**, rat / checkstyle / spotless / dependency-analyze / 
enforcer clean.
   
   End to end on 4.3.1.2, through ThingsBoard's REST API: telemetry and 
attributes written and confirmed in IoTDB; five read shapes correct — raw 
range, latest, attributes, fixed-window aggregation (AVG and COUNT arithmetic 
exact), and calendar aggregation in a non-UTC zone. ThingsBoard's own internal 
telemetry flows through the module as well, so the whole platform's persistence 
is served by it.
   
   ## Points I'd appreciate review on
   
   - **The guard's semantics changed, and this is the part I would most like a 
second opinion on.** In #113 it was reviewed as "fail loudly on a conflict"; it 
is now "withdraw the conflicting bean and log". My reasoning is that we are 
supplying a switch ThingsBoard does not have rather than fighting its design, 
and that the withdrawal sits behind two explicit properties and a WARN. But how 
far an extension module may go in mutating its host's bean definitions is a 
judgement I do not want to make alone. The alternative is to retreat — mark 
attributes as pending ThingsBoard-side selector support, which is honest but 
gives up the capability. **I am happy to take either, or to take this to dev@ 
first if that is the better route.**
   
   - **The `dependency:analyze` suppression.** It is the honest option as far 
as I can tell, but it does mean a static check no longer guards that 
dependency. If there is a way to make the runtime use visible to the analyzer 
instead, I would rather do that.
   
   - **Guard test coverage is partial.** Four tests where there were none: 
withdrawal, the zero-replacement refusal, the no-op path, ordering. Not yet 
covered: a bean whose type will not resolve, a factory that cannot withdraw, 
the WARN assertion (the module's test classpath has no logging backend), and an 
`ApplicationContextRunner` pair for the selector-off and end-to-end wiring 
cases. Happy to add them here if you would like them before merge.
   
   Happy to iterate.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to