You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by "gnodet (via GitHub)" <gi...@apache.org> on 2026/10/01 16:04:52 UTC
[PR] CAMEL-24038: Fix flaky AsyncWiretapTest - use thread-safe collections in mock telemetry infrastructure [camel]
gnodet opened a new pull request, #27226:
URL: https://github.com/apache/camel/pull/27226
## Summary
Fixes the flaky `AsyncWiretapTest` in `camel-telemetry` and `camel-telemetry-dev` by replacing non-thread-safe collections in the mock telemetry infrastructure with their concurrent equivalents.
Resolves: https://issues.apache.org/jira/browse/CAMEL-24038
## Root Cause
The wiretap EIP creates async exchanges processed on different threads, causing concurrent access on plain `HashMap` and `ArrayList` instances in the mock infrastructure — collections that provide no memory-visibility guarantees across threads.
This directly explains the intermittent `expected: <7> but was: <6>` and `expected: <10> but was: <N>` failures seen in CI: spans silently lost due to HashMap's undefined concurrent-modification behavior.
Previous fixes (PRs #24636, #25331) addressed timing via Awaitility but not the underlying data-race root cause. This PR fixes the root cause.
## Changes
### `camel-telemetry` (test classes)
**`MockTracer.java`** — `MockSpanLifecycleManager.inMemoryStorageMap`
- `HashMap` → `ConcurrentHashMap`
- `activate()` and `close()` are called from exchange threads; `traces()` is called from the test thread
**`MockSpanAdapter.java`** — `tags` and `logEntries`
- `HashMap` → `ConcurrentHashMap` for `tags` (the `isDone` tag is written from an exchange thread and read from the test thread without memory barriers)
- `ArrayList` → `Collections.synchronizedList` for `logEntries`
- Guard `setComponent()` and `setTag()` against null values (ConcurrentHashMap rejects nulls; some decorator tests pass null via Mockito mocks)
### `camel-telemetry-dev` (production class used as test infrastructure)
**`DevSpanAdapter.java`** — `tags` and `logEntries`
- Same pattern as `MockSpanAdapter`: `HashMap` → `ConcurrentHashMap`, `ArrayList` → `Collections.synchronizedList`
- `setLogEntries()` wraps the incoming list in a synchronized wrapper
### Not changed
`InMemoryCollector` — already protects all access with a `ReentrantLock` ✓
## Testing
All existing tests in both modules pass locally (`mvn test` on both `camel-telemetry` and `camel-telemetry-dev`).
--
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: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-24038: Fix flaky AsyncWiretapTest - use thread-safe collections in mock telemetry infrastructure [camel]
Posted by "github-actions[bot] (via GitHub)" <gi...@apache.org>.
github-actions[bot] commented on PR #27226:
URL: https://github.com/apache/camel/pull/27226#issuecomment-5941608474
<!-- ci-tested-modules -->
:test_tube: **CI tested the following changed modules:**
- `components/camel-telemetry-dev`
- `components/camel-telemetry`
:repeat: **1 test passed only after a retry on JDK 17** (1 retried attempt)
<details><summary>Recovered flaky tests on JDK 17 (1)</summary>
| Module | Test | Failed attempts | First failure |
| --- | --- | --- | --- |
| `dsl/camel-jbang/camel-jbang-plugin-tui` | `TuiShellHistorySupportTest.positiveLimitUsesCamelHistoryFile(Path)` | 1 | expected: /tmp/junit-1874832076090908386/.camel/tui-shell.history but was: /tmp/junit-7883354621010714067/.camel/tui-shell.history |
> :information_source: These tests did **not** fail the build. Surefire retried them and they passed.
> Retries are enabled project-wide by `surefire.rerunFailingTestsCount` in `parent/pom.xml`.
</details>
---
<details><summary>:microscope: Scalpel shadow comparison — Scalpel: 10 of 697 tested, 27 compile-only — current: 21 all tested</summary>
[Maveniverse Scalpel](https://github.com/maveniverse/scalpel) detected **10 affected modules** (current approach: 21).
**Skip-tests mode would test 10 modules** (2 direct + 8 downstream), **skip tests for 27** (generated code, meta-modules)
<details><summary>Modules only in current approach (11)</summary>
- `camel-ai-observability`
- `camel-langchain4j-agent`
- `camel-langchain4j-chat`
- `camel-langchain4j-embeddings`
- `camel-langchain4j-embeddingstore`
- `camel-mcp-server`
- `camel-micrometer-observability`
- `camel-observability-services`
- `camel-openai`
- `camel-opentelemetry2`
- `camel-spring-ai-chat`
</details>
<details><summary>Modules Scalpel would test (10)</summary>
- `camel-jbang-mcp` ← downstream of org.apache.camel:camel-catalog
- `camel-jbang-plugin-mcp` ← downstream of org.apache.camel:camel-jbang-core
- `camel-jbang-plugin-route-parser` ← downstream of org.apache.camel:camel-route-parser
- `camel-jbang-plugin-tui` ← downstream of org.apache.camel:camel-catalog
- `camel-jbang-plugin-validate` ← downstream of org.apache.camel:camel-yaml-dsl-validator
- `camel-launcher-container` ← downstream of org.apache.camel:camel-launcher
- `camel-telemetry` ← components/camel-telemetry/src/test/java/org/apache/camel/telemetry/mock/MockSpanAdapter.java, components/camel-telemetry/src/test/java/org/apache/camel/telemetry/mock/MockTracer.java
- `camel-telemetry-dev` ← components/camel-telemetry-dev/src/main/java/org/apache/camel/telemetrydev/DevSpanAdapter.java
- `camel-yaml-dsl-validator` ← downstream of org.apache.camel:camel-catalog
- `camel-yaml-dsl-validator-maven-plugin` ← downstream of org.apache.camel:camel-yaml-dsl-validator
</details>
<details><summary>Modules with tests skipped (27)</summary>
- `apache-camel`
- `camel-allcomponents`
- `camel-catalog`
- `camel-catalog-console`
- `camel-catalog-maven`
- `camel-catalog-suggest`
- `camel-componentdsl`
- `camel-endpointdsl`
- `camel-endpointdsl-support`
- `camel-itest`
- `camel-jbang-core`
- `camel-jbang-it`
- `camel-jbang-main`
- `camel-jbang-plugin-edit`
- `camel-jbang-plugin-generate`
- `camel-jbang-plugin-kubernetes`
- `camel-jbang-plugin-test`
- `camel-kamelet-main`
- `camel-launcher`
- `camel-report-maven-plugin`
- `camel-route-parser`
- `camel-yaml-dsl`
- `camel-yaml-dsl-deserializers`
- `camel-yaml-dsl-maven-plugin`
- `coverage`
- `docs`
- `dummy-component`
</details>
> :information_source: Shadow mode — Scalpel observes but does not affect test execution. [Learn more](https://github.com/maveniverse/scalpel)
</details>
<details><summary>All tested modules (48 modules, 8m 1s total)</summary>
**Total reactor time:** 8m 1s
| Module | Duration | Status |
| --- | --- | --- |
| Camel :: AI :: MCP Server | 52.8s | SUCCESS |
| Camel :: Launcher | 50.7s | SUCCESS |
| Camel :: JBang :: MCP | 44.6s | SUCCESS |
| Camel :: AI :: OpenAI | 39.8s | SUCCESS |
| Camel :: JBang :: Plugin :: TUI | 39.7s | SUCCESS |
| Camel :: AI :: LangChain4j :: EmbeddingStore | 25.0s | SUCCESS |
| Camel :: Catalog :: Camel Catalog | 23.8s | SUCCESS |
| Camel :: Component DSL | 23.3s | SUCCESS |
| Camel :: YAML DSL | 20.2s | SUCCESS |
| Camel :: YAML DSL :: Validator | 18.0s | SUCCESS |
| Camel :: JBang :: Plugin :: Kubernetes | 17.7s | SUCCESS |
| Camel :: Docs | 15.2s | SUCCESS |
| Camel :: Spring AI :: Chat | 12.2s | SUCCESS |
| Camel :: Kamelet Main | 11.5s | SUCCESS |
| Camel :: AI :: LangChain4j :: Agent | 11.0s | SUCCESS |
| Camel :: JBang :: Plugin :: Testing | 7.5s | SUCCESS |
| Camel :: Catalog :: Camel Report Maven Plugin | 7.2s | SUCCESS |
| Camel :: Catalog :: Camel Route Parser | 7.1s | SUCCESS |
| Camel :: YAML DSL :: Deserializers | 6.7s | SUCCESS |
| Camel :: YAML DSL :: Validator Maven Plugin | 6.3s | SUCCESS |
| Camel :: AI :: Observability | 6.0s | SUCCESS |
| Camel :: AI :: LangChain4j :: Chat | 6.0s | SUCCESS |
| Camel :: JBang :: Plugin :: Validate | 5.1s | SUCCESS |
| Camel :: All Components Sync point | 4.0s | SUCCESS |
| Camel :: Catalog :: Maven | 2.8s | SUCCESS |
| Camel :: Catalog :: Suggest (deprecated) | 2.5s | SUCCESS |
| Camel :: YAML DSL :: Maven Plugins | 2.5s | SUCCESS |
| Camel :: Assembly | 1.7s | SUCCESS |
| Camel :: Coverage | 1.5s | SUCCESS |
| Camel :: Observability Services | 1.2s | SUCCESS |
| Camel :: JBang :: Plugin :: Edit | 1.2s | SUCCESS |
| Camel :: JBang :: Plugin :: Generate | 1.1s | SUCCESS |
| Camel :: Catalog :: Console | 0.9s | SUCCESS |
| Camel :: JBang :: Integration tests | 0.9s | SUCCESS |
| Camel :: Endpoint DSL :: Support | 0.8s | SUCCESS |
| Camel :: JBang :: Plugin :: MCP | 0.7s | SUCCESS |
| Camel :: JBang :: Main | 0.7s | SUCCESS |
| Camel :: Launcher :: Container | 0.7s | SUCCESS |
| Camel :: Catalog :: Dummy Component | 0.5s | SUCCESS |
| Camel :: JBang :: Plugin :: Route Parser | 0.5s | SUCCESS |
| Camel :: AI :: LangChain4j :: Embedding | n/a | |
| Camel :: Common Telemetry | n/a | |
| Camel :: Endpoint DSL | n/a | |
| Camel :: Integration Tests | n/a | |
| Camel :: JBang :: Core | n/a | |
| Camel :: Micrometer :: Observability 2 | n/a | |
| Camel :: Opentelemetry 2 | n/a | |
| Camel :: Telemetry :: Dev | n/a | |
**Top 20 slowest modules:**
- `Camel :: AI :: MCP Server` (52.8s)
- `Camel :: Launcher` (50.7s)
- `Camel :: JBang :: MCP` (44.6s)
- `Camel :: AI :: OpenAI` (39.8s)
- `Camel :: JBang :: Plugin :: TUI` (39.7s)
- `Camel :: AI :: LangChain4j :: EmbeddingStore` (25.0s)
- `Camel :: Catalog :: Camel Catalog` (23.8s)
- `Camel :: Component DSL` (23.3s)
- `Camel :: YAML DSL` (20.2s)
- `Camel :: YAML DSL :: Validator` (18.0s)
- `Camel :: JBang :: Plugin :: Kubernetes` (17.7s)
- `Camel :: Docs` (15.2s)
- `Camel :: Spring AI :: Chat` (12.2s)
- `Camel :: Kamelet Main` (11.5s)
- `Camel :: AI :: LangChain4j :: Agent` (11.0s)
- `Camel :: JBang :: Plugin :: Testing` (7.5s)
- `Camel :: Catalog :: Camel Report Maven Plugin` (7.2s)
- `Camel :: Catalog :: Camel Route Parser` (7.1s)
- `Camel :: YAML DSL :: Deserializers` (6.7s)
- `Camel :: YAML DSL :: Validator Maven Plugin` (6.3s)
</details>
---
:gear: [View full build and test results](https://github.com/apache/camel/actions/runs/36889260829)
--
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: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-24038: Fix flaky AsyncWiretapTest - use thread-safe collections in mock telemetry infrastructure [camel]
Posted by "github-actions[bot] (via GitHub)" <gi...@apache.org>.
github-actions[bot] commented on PR #27226:
URL: https://github.com/apache/camel/pull/27226#issuecomment-5935380852
:star2: Thank you for your contribution to the Apache Camel project! :star2:
:robot: CI automation will test this PR automatically.
:camel: Apache Camel Committers, please review the following items:
* First-time contributors **require MANUAL approval** for the GitHub Actions to run
* You can use the command `/component-test (camel-)component-name1 (camel-)component-name2..` to request a test from the test bot although they are normally detected and executed by CI.
* You can label PRs using `skip-tests` and `test-dependents` to fine-tune the checks executed by this PR.
* Build and test logs are available in the summary page. **Only** [Apache Camel committers](https://camel.apache.org/community/team/#committers) have access to the summary.
:warning: Be careful when sharing logs. Review their contents before sharing them publicly.
--
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: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-24038: Fix flaky AsyncWiretapTest - use thread-safe collections in mock telemetry infrastructure [camel]
Posted by "davsclaus (via GitHub)" <gi...@apache.org>.
davsclaus merged PR #27226:
URL: https://github.com/apache/camel/pull/27226
--
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: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-24038: Fix flaky AsyncWiretapTest - use thread-safe collections in mock telemetry infrastructure [camel]
Posted by "davsclaus (via GitHub)" <gi...@apache.org>.
davsclaus commented on code in PR #27226:
URL: https://github.com/apache/camel/pull/27226#discussion_r4163317945
##########
components/camel-telemetry-dev/src/main/java/org/apache/camel/telemetrydev/DevSpanAdapter.java:
##########
@@ -29,8 +31,11 @@
public class DevSpanAdapter implements Span {
- private List<LogEntry> logEntries = new ArrayList<>();
- private final Map<String, String> tags = new HashMap<>();
+ // ConcurrentHashMap: tags (including isDone) are written from exchange threads and read
+ // from the collector thread without explicit synchronization.
Review Comment:
Nit (optional, non-blocking): there's no dedicated collector thread. The reader is the exchange thread that closes the last span (`InMemoryCollector.get()` and later `DevTraceFormat`). Maybe:
```suggestion
// ConcurrentHashMap: tags (including isDone) are written from exchange threads and read
// from other exchange threads when the trace is collected and formatted.
```
##########
components/camel-telemetry-dev/src/main/java/org/apache/camel/telemetrydev/DevSpanAdapter.java:
##########
@@ -58,7 +65,9 @@ public void setError(boolean error) {
@JsonAnySetter
@Override
public void setTag(String key, String value) {
- this.tags.put(key, value);
+ if (key != null && value != null) {
Review Comment:
Note for users of camel-telemetry-dev: tags with null values are no longer kept, so the JSON trace output no longer contains `"key": null` entries. I think that's fine (reads still return null), just pointing it out.
##########
components/camel-telemetry-dev/src/main/java/org/apache/camel/telemetrydev/DevSpanAdapter.java:
##########
@@ -71,11 +80,13 @@ public void log(Map<String, String> fields) {
}
public List<LogEntry> getLogEntries() {
- return new ArrayList<>(this.logEntries);
+ synchronized (logEntries) {
Review Comment:
Nit (optional, non-blocking): the `synchronized (logEntries)` block isn't strictly needed here (same in `MockSpanAdapter.logEntries()`). `new ArrayList<>(Collection)` calls `toArray()`, and the synchronized list already locks that call. It does no harm, so fine to keep.
--
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: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org