ym0506 opened a new issue, #39765:
URL: https://github.com/apache/shardingsphere/issues/39765

   ## Bug Report
   
   ### Which version of ShardingSphere did you use?
   
   Current `master`, commit `bd48f5204c8bbfcb87f7e52fd8d39f8457946520` 
(`5.5.4-SNAPSHOT`). The deterministic regression uses OpenTelemetry SDK 1.58.0 
and Java 17.0.15.
   
   ### Which project did you use? ShardingSphere-JDBC or ShardingSphere-Proxy?
   
   The ShardingSphere Agent OpenTelemetry plugin's JDBC executor callback 
advice. I investigated this while checking physical SQL execution visibility 
for a ShardingSphere-JDBC routing-contract project. The current-master 
reproduction is an advice-level unit test with mocked JDBC metadata; it does 
not require a database or collector.
   
   ### Expected behavior
   
   Two overlapping per-unit `execute` invocations on the same JDBC executor 
callback should produce two distinct completed `/ShardingSphere/executeSQL/` 
spans. Each span should preserve its own SQL attributes and success/error 
outcome. An exception in one invocation must not change or disappear into the 
other invocation's span.
   
   ### Actual behavior
   
   A deterministic two-thread test starts invocation A, starts invocation B, 
completes A successfully, then completes B with an exception. Only one span is 
exported: B's span is ended by A's completion hook. A's span is never ended, 
and B's error is not recorded because its span has already ended.
   
   The test fails on unchanged current-master production code with:
   
   ```text
   OpenTelemetryJDBCExecutorCallbackAdviceTest.assertConcurrentInvocations
   Expected: is <2>
        but: was <1>
   Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
   ```
   
   ### Reason analyze (If you can)
   
   `OpenTelemetryJDBCExecutorCallbackAdvice.recordExecuteInfo` stores each 
started span in `TargetAdviceObject.setAttachment`. That attachment is a single 
field on the callback object. `afterMethod` and `onThrowing` read the same 
field, so overlapping invocations overwrite each other's span.
   
   The invocation sequence is:
   
   ```text
   A.before: attachment = spanA
   B.before: attachment = spanB
   A.after:  end(spanB) with OK
   B.throw:  record error on already-ended spanB
   B.after:  end already-ended spanB again
   ```
   
   `InstanceMethodAdviceExecutor` also invokes `afterMethod` in `finally` after 
`onThrowing`; a fix needs to handle this lifecycle without completing an outer 
nested invocation. The executor passes the same `Object[] args` reference 
through all hooks for one invocation, providing an existing invocation identity.
   
   ### Steps to reproduce the behavior, such as: SQL to execute, sharding rule 
configuration, when exception occur etc.
   
   1. Create one `OpenTelemetryJDBCExecutorCallbackAdvice` and one callback 
fixture implementing `TargetAdviceObject`.
   2. Use an `InMemorySpanExporter` and `SimpleSpanProcessor` with 
OpenTelemetry SDK.
   3. Prepare two argument arrays for `SELECT 1` and `SELECT 2`.
   4. Use two executor threads and three bounded `CountDownLatch` instances to 
enforce the exact sequence above. Use the same argument array for all hooks 
belonging to one invocation, matching `InstanceMethodAdviceExecutor`.
   5. Assert two completed span IDs, A's `SELECT 1`/OK/no-exception attributes, 
and B's `SELECT 2`/ERROR/one-exception attributes.
   
   ### Example codes for reproduce this issue (such as a github link).
   
   The [test-only reproducer 
commit](https://github.com/ym0506/shardingsphere/commit/92571c88362bf71b2b3e49d1ec94834fd67854a7)
 keeps production code at the base above. Its 
`OpenTelemetryJDBCExecutorCallbackAdviceTest.assertConcurrentInvocations` 
compiles and deterministically fails with expected 2 / actual 1. Run:
   
   ```sh
   ./mvnw -B -pl agent/plugins/tracing/type/opentelemetry -am \
     
-Dtest=OpenTelemetryJDBCExecutorCallbackAdviceTest#assertConcurrentInvocations \
     -Dsurefire.failIfNoSpecifiedTests=false test
   ```
   
   ### Separate 5.5.3/MySQL corroboration
   
   I also reran the [runtime-absent fixture at 
da1240b](https://github.com/ym0506/routecontract/blob/da1240b46765d91695922c28a7d79dc2eb66e8fc/docs/agent-runtime-absent-reproducer.md)
 on 2026-09-08 with the SHA-512-verified official Agent 5.5.3 and MySQL 8.4.11. 
RouteContract API/hook/SPI/artifact are absent from the forked runtime; 
datasource-proxy is the backing-callback count oracle. Across 20 controls and 
20 forced two-way fan-outs, it reports 60 successful backing callbacks but only 
40 completed execute spans (20 control, 20 fan-out). This is an exact 
forced-overlap fixture, not a production loss rate or current-master database 
test.
   
   ### Fix direction to discuss
   
   An invocation-keyed local candidate passes concurrency, nesting, 
failed-before and exception-then-finally tests. Applying only the two 
corresponding advice classes to an explicitly modified 5.5.3 Agent also gives 
60 completed spans for the same 60-callback MySQL fixture, including two 
distinct-target children for every fan-out root. This is a local experimental 
build, not an official release.
   
   I would appreciate guidance on the invocation-state owner before proposing a 
production PR. A per-thread weak-key map avoids strongly retaining abandoned 
argument arrays, but stale Span values need a later map access after GC. 
Dynamic `agent-plugins-enabled` changes can skip completion hooks. The 
candidate also adds about 40 B and 62 ns per invocation in a local 
advice/SDK-only loop, excluding database and exporter work. I am not treating 
that prototype as performance-neutral or ready to merge.
   
   AI assistance: OpenAI Codex assisted with investigation, reproductions, 
tests and the experimental candidate.
   


-- 
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