Skip to content

Fix flaky tests: Disruptor, Seda, Scheduler (batch 16)#24804

Merged
davsclaus merged 3 commits into
apache:mainfrom
gnodet:fix/batch16-disruptor-seda-scheduler
Jul 18, 2026
Merged

Fix flaky tests: Disruptor, Seda, Scheduler (batch 16)#24804
davsclaus merged 3 commits into
apache:mainfrom
gnodet:fix/batch16-disruptor-seda-scheduler

Conversation

@gnodet

@gnodet gnodet commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Claude Code on behalf of gnodet

Summary

Fix 3 flaky tests identified by Develocity, each with a distinct root cause:

1. DisruptorBlockWhenFullTest.testDisruptorExceptionWhenFull (11 flaky / 715 runs — 1.5%)

Root cause: The delay(100) EIP defaults to async mode. The consumer's onEvent() returns in microseconds because the delay is scheduled on a background executor — it does not block the ring buffer consumption. Under CI load, the buffer never fills up and tryNext() succeeds instead of throwing InsufficientCapacityException.

Fix: Add .syncDelayed() so the consumer blocks for the full 100ms inside onEvent(), keeping the ring buffer full long enough for the producer to reliably hit the exception.

2. SedaBlockWhenFullTest.testAsyncSedaBlockingWhenFull (65 flaky / 716 runs — 9.1%)

Root cause: With blockWhenFull=true and async sends, all messages eventually arrive (they block and wait for queue space). The exact-count assertion (setExpectedMessageCount(2)) opens its CountDownLatch after 2 messages, then races against additional messages arriving before assertEquals runs — causing "expected 2 but was 3+".

Fix: Switch to expectedMinimumMessageCount(2) which uses a >= check. The test's purpose is verifying that blocked messages eventually succeed, not that exactly N arrive.

3. SchedulerNoPolledMessagesTest (75 flaky / 716 runs — 10.5%)

Root cause: The arrives().afterPrevious() MockEndpoint API has a subtle race: when computing "after previous", it actually compares with the next message's timestamp (if already received), not the previous one. A 4th message arriving ~100ms after the 3rd violates the 200ms lower bound intended for the backoff gap between messages 1→2.

Prior widening attempts (4× wider windows) didn't help because the race is structural, not a matter of window width.

Fix: Replace the fragile timing API with direct timestamp comparison on already-received (immutable) exchanges after assertIsSatisfied() completes. This is immune to additional messages arriving concurrently.

Test plan

  • DisruptorBlockWhenFullTest — 2 tests pass (both blocking and exception variants)
  • SedaBlockWhenFullTest — 4 tests pass (all variants including the fixed async one)
  • SchedulerNoPolledMessagesTest — passes with direct timestamp assertions
  • CI green on the full build

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 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 have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-disruptor
  • core/camel-core

🔬 Scalpel shadow comparison — Scalpel: 24 tested, 0 compile-only — current: 9 all tested

Maveniverse Scalpel detected 24 affected modules (current approach: 9).

⚠️ Modules only in Scalpel (23)
  • camel-console
  • camel-core
  • camel-csimple-joor
  • camel-datasonnet
  • camel-groovy
  • camel-hl7
  • camel-javascript
  • camel-joor
  • camel-jq
  • camel-jsonpath
  • camel-main
  • camel-management
  • camel-mvel
  • camel-ognl
  • camel-platform-http-jolokia
  • camel-python
  • camel-saxon
  • camel-spring-xml
  • camel-stax
  • camel-xml-io-dsl
  • camel-xml-jaxb-dsl
  • camel-xml-jaxb-dsl-test-definition
  • camel-xml-jaxb-dsl-test-spring
Modules only in current approach (8)
  • camel-jbang-mcp
  • camel-jbang-plugin-mcp
  • camel-jbang-plugin-route-parser
  • camel-jbang-plugin-tui
  • camel-jbang-plugin-validate
  • camel-launcher-container
  • camel-yaml-dsl-validator
  • camel-yaml-dsl-validator-maven-plugin

Skip-tests mode would test 24 modules (2 direct + 22 downstream), skip tests for 0 (generated code, meta-modules)

Modules Scalpel would test (24)
  • camel-console
  • camel-core
  • camel-csimple-joor
  • camel-datasonnet
  • camel-disruptor
  • camel-groovy
  • camel-hl7
  • camel-javascript
  • camel-joor
  • camel-jq
  • camel-jsonpath
  • camel-main
  • camel-management
  • camel-mvel
  • camel-ognl
  • camel-platform-http-jolokia
  • camel-python
  • camel-saxon
  • camel-spring-xml
  • camel-stax
  • camel-xml-io-dsl
  • camel-xml-jaxb-dsl
  • camel-xml-jaxb-dsl-test-definition
  • camel-xml-jaxb-dsl-test-spring

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

⚠️ Some tests are disabled on GitHub Actions (@DisabledIfSystemProperty(named = "ci.env.name")) and require manual verification:

  • core/camel-core: 2 test(s) disabled on GitHub Actions
All tested modules (470 modules)
  • Camel :: AI :: A2A
  • Camel :: AI :: ChatScript
  • Camel :: AI :: Deep Java Library
  • Camel :: AI :: Docling
  • Camel :: AI :: Hugging Face
  • Camel :: AI :: KServe
  • Camel :: AI :: LangChain4j :: Agent
  • Camel :: AI :: LangChain4j :: Chat
  • Camel :: AI :: LangChain4j :: Core
  • Camel :: AI :: LangChain4j :: Embedding
  • Camel :: AI :: LangChain4j :: EmbeddingStore
  • Camel :: AI :: LangChain4j :: Tokenizer
  • Camel :: AI :: LangChain4j :: Tools
  • Camel :: AI :: LangChain4j :: Web Search
  • Camel :: AI :: Milvus
  • Camel :: AI :: Neo4j
  • Camel :: AI :: OpenAI
  • Camel :: AI :: PGVector
  • Camel :: AI :: Pinecone
  • Camel :: AI :: Qdrant
  • Camel :: AI :: TensorFlow Serving
  • Camel :: AI :: Tool
  • Camel :: AI :: Weaviate
  • Camel :: AMQP
  • Camel :: AS2 :: API
  • Camel :: AS2 :: Component
  • Camel :: ASN.1
  • Camel :: AWS CloudTrail
  • Camel :: AWS Config
  • Camel :: AWS Redshift Data
  • Camel :: AWS Rekognition
  • Camel :: AWS Security Hub
  • Camel :: AWS Step Functions
  • Camel :: AWS Timestream
  • Camel :: AWS2 :: Transcribe
  • Camel :: AWS2 Athena
  • Camel :: AWS2 Bedrock
  • Camel :: AWS2 CW
  • Camel :: AWS2 Comprehend
  • Camel :: AWS2 DDB
  • Camel :: AWS2 EC2
  • Camel :: AWS2 ECS
  • Camel :: AWS2 EKS
  • Camel :: AWS2 Eventbridge
  • Camel :: AWS2 IAM
  • Camel :: AWS2 KMS
  • Camel :: AWS2 Kinesis
  • Camel :: AWS2 Lambda
  • Camel :: AWS2 MQ
  • Camel :: AWS2 MSK
  • Camel :: AWS2 Parameter Store
  • Camel :: AWS2 Polly
  • Camel :: AWS2 S3
  • Camel :: AWS2 S3 Vectors
  • Camel :: AWS2 SES
  • Camel :: AWS2 SNS
  • Camel :: AWS2 SQS
  • Camel :: AWS2 STS
  • Camel :: AWS2 Secrets Manager
  • Camel :: AWS2 Textract
  • Camel :: AWS2 Translate
  • Camel :: ActiveMQ 5.x
  • Camel :: ActiveMQ 6.x
  • Camel :: All Core Sync point
  • Camel :: ArangoDB
  • Camel :: Archetypes
  • Camel :: Archetypes :: API Component
  • Camel :: Archetypes :: Component
  • Camel :: Archetypes :: Data Format
  • Camel :: Archetypes :: Java Router
  • Camel :: Archetypes :: Main
  • Camel :: Archetypes :: Spring XML Based Router (deprecated)
  • Camel :: Asterisk
  • Camel :: Atmosphere WebSocket Servlet
  • Camel :: Atom
  • Camel :: Attachments
  • Camel :: Avro
  • Camel :: Avro RPC
  • Camel :: Azure :: CosmosDB
  • Camel :: Azure :: Event Grid
  • Camel :: Azure :: Event Hubs
  • Camel :: Azure :: Files
  • Camel :: Azure :: Functions
  • Camel :: Azure :: Key Vault
  • Camel :: Azure :: Schema Registry
  • Camel :: Azure :: ServiceBus
  • Camel :: Azure :: Storage Blob
  • Camel :: Azure :: Storage Datalake
  • Camel :: Azure :: Storage Queue
  • Camel :: Barcode
  • Camel :: Base64
  • Camel :: Bean validator
  • Camel :: BeanIO
  • Camel :: Bindy
  • Camel :: Bonita
  • Camel :: Box :: Component
  • Camel :: Braintree
  • Camel :: CBOR
  • Camel :: CM SMS
  • Camel :: CSV
  • Camel :: CXF :: Common
  • Camel :: CXF :: Common :: Spring
  • Camel :: CXF :: REST
  • Camel :: CXF :: REST :: Spring
  • Camel :: CXF :: SOAP
  • Camel :: CXF :: SOAP :: Spring
  • Camel :: CXF :: Transport
  • Camel :: CXF :: Transport :: Spring
  • Camel :: Caffeine
  • Camel :: Camunda
  • Camel :: Cassandra CQL
  • Camel :: Chunk
  • Camel :: ClickUp
  • Camel :: CloudEvents
  • Camel :: CoAP
  • Camel :: Cometd
  • Camel :: Common Telemetry
  • Camel :: Common Tracing (deprecated)
  • Camel :: Console
  • Camel :: Consul
  • Camel :: Core
  • Camel :: CouchDB
  • Camel :: Couchbase
  • Camel :: Cron
  • Camel :: Crypto
  • Camel :: Crypto PGP
  • Camel :: CyberArk Vault
  • Camel :: DFDL
  • Camel :: DHIS2
  • Camel :: DHIS2 :: Parent
  • Camel :: DHIS2 API
  • Camel :: DNS
  • Camel :: DSL :: CLI Connector
  • Camel :: DSL :: CLI Debug
  • Camel :: DSL :: Modeline
  • Camel :: Dapr
  • Camel :: DataSonnet
  • Camel :: Debezium :: Common
  • Camel :: Debezium :: DB2
  • Camel :: Debezium :: Maven Plugin
  • Camel :: Debezium :: MongoDB
  • Camel :: Debezium :: MySQL
  • Camel :: Debezium :: Oracle
  • Camel :: Debezium :: PostgreSQL
  • Camel :: Debezium :: SQL Server
  • Camel :: Debugging
  • Camel :: Diagram
  • Camel :: DigitalOcean (deprecated)
  • Camel :: Disruptor
  • Camel :: Docker
  • Camel :: Drill
  • Camel :: Dropbox
  • Camel :: Dynamic Router
  • Camel :: Ehcache
  • Camel :: ElasticSearch Rest Client
  • Camel :: Elasticsearch Java API Client
  • Camel :: Event
  • Camel :: Exec
  • Camel :: FHIR
  • Camel :: FOP
  • Camel :: FTP
  • Camel :: Fastjson
  • Camel :: File Watch
  • Camel :: FlatPack
  • Camel :: Flink
  • Camel :: Flowable
  • Camel :: Fory
  • Camel :: Freemarker
  • Camel :: Geocoder
  • Camel :: Git
  • Camel :: GitHub2
  • Camel :: Google :: BigQuery
  • Camel :: Google :: Calendar
  • Camel :: Google :: Common
  • Camel :: Google :: Drive
  • Camel :: Google :: Firestore
  • Camel :: Google :: Functions
  • Camel :: Google :: Mail
  • Camel :: Google :: PubSub
  • Camel :: Google :: Secret Manager
  • Camel :: Google :: Sheets
  • Camel :: Google :: Speech To Text
  • Camel :: Google :: Storage
  • Camel :: Google :: Text To Speech
  • Camel :: Google :: Vertex AI
  • Camel :: Google :: Vision
  • Camel :: GraphQL
  • Camel :: Grok
  • Camel :: Groovy
  • Camel :: Gson
  • Camel :: HL7
  • Camel :: HTTP
  • Camel :: HTTP :: Base
  • Camel :: HTTP :: Common
  • Camel :: HashiCorp :: Key Vault
  • Camel :: HazelCast
  • Camel :: Headers Map (deprecated)
  • Camel :: Huawei Cloud :: DMS
  • Camel :: Huawei Cloud :: FaceRecognition
  • Camel :: Huawei Cloud :: FunctionGraph
  • Camel :: Huawei Cloud :: IAM
  • Camel :: Huawei Cloud :: ImageRecognition
  • Camel :: Huawei Cloud :: OBS
  • Camel :: Huawei Cloud :: SimpleNotification
  • Camel :: IBM :: Cloud Object Storage
  • Camel :: IBM :: Secrets Manager
  • Camel :: IBM :: Watson Discovery
  • Camel :: IBM :: Watson Language
  • Camel :: IBM :: Watson Speech to Text
  • Camel :: IBM :: Watson Text to Speech
  • Camel :: IBM :: watsonx.ai
  • Camel :: IBM :: watsonx.data
  • Camel :: IEC 60870 (deprecated)
  • Camel :: IRC (deprecated)
  • Camel :: ISO-8583
  • Camel :: Iggy
  • Camel :: Ignite
  • Camel :: Infinispan :: Common
  • Camel :: Infinispan :: Embedded
  • Camel :: Infinispan :: Remote
  • Camel :: InfluxDB
  • Camel :: InfluxDB2
  • Camel :: Integration Tests :: Stream Caching Tests
  • Camel :: IronMQ
  • Camel :: JAXB
  • Camel :: JBang :: Console
  • Camel :: JBang :: MCP
  • Camel :: JBang :: Plugin :: MCP
  • Camel :: JBang :: Plugin :: Route Parser
  • Camel :: JBang :: Plugin :: TUI
  • Camel :: JBang :: Plugin :: Validate
  • Camel :: JCR
  • Camel :: JCache
  • Camel :: JDBC
  • Camel :: JGroups
  • Camel :: JGroups Raft
  • Camel :: JIRA
  • Camel :: JMS
  • Camel :: JMX
  • Camel :: JOOQ
  • Camel :: JPA
  • Camel :: JQ
  • Camel :: JSON validator
  • Camel :: JSON-B
  • Camel :: JSONATA
  • Camel :: JSon Path
  • Camel :: JSonApi
  • Camel :: JSoup
  • Camel :: JTA
  • Camel :: Jackson
  • Camel :: Jackson 3
  • Camel :: Jackson 3 Avro
  • Camel :: Jackson 3 Protobuf
  • Camel :: Jackson 3 XML
  • Camel :: Jackson Avro
  • Camel :: Jackson Protobuf
  • Camel :: Jackson XML
  • Camel :: Jandex
  • Camel :: Jasypt
  • Camel :: Java DSL with jOOR
  • Camel :: Java Flight Recorder
  • Camel :: Java Template Engine
  • Camel :: Java Toolbox for IBM i
  • Camel :: JavaScript
  • Camel :: Jetty
  • Camel :: Jetty :: Common
  • Camel :: Jolt
  • Camel :: Jsch
  • Camel :: Jslt
  • Camel :: JsonPatch (deprecated)
  • Camel :: Kafka
  • Camel :: Kamelet
  • Camel :: Kamelet Main :: Support
  • Camel :: Keycloak
  • Camel :: Knative API
  • Camel :: Knative Component
  • Camel :: Knative HTTP
  • Camel :: Kubernetes
  • Camel :: Kudu
  • Camel :: LDAP
  • Camel :: LDIF
  • Camel :: LZF
  • Camel :: Launcher :: Container
  • Camel :: LevelDB (deprecated)
  • Camel :: Long-Running-Action
  • Camel :: Lucene
  • Camel :: Lumberjack
  • Camel :: MDC
  • Camel :: MINA
  • Camel :: MINA SFTP
  • Camel :: MLLP
  • Camel :: MVEL
  • Camel :: Mail
  • Camel :: Mail :: Microsoft OAuth
  • Camel :: Main
  • Camel :: Management
  • Camel :: MapStruct
  • Camel :: Master
  • Camel :: Maven Plugins :: Camel API Component Plugin
  • Camel :: Maven Plugins :: Camel Maven Plugin
  • Camel :: Maven Plugins :: OpenApi REST DSL Generator
  • Camel :: Metrics
  • Camel :: MicroProfile :: Config
  • Camel :: MicroProfile :: Fault Tolerance
  • Camel :: MicroProfile :: Health
  • Camel :: Micrometer
  • Camel :: Micrometer :: Observability 2
  • Camel :: Micrometer :: Observation (deprecated)
  • Camel :: Micrometer :: Prometheus
  • Camel :: Milo
  • Camel :: MinIO
  • Camel :: MongoDB
  • Camel :: MongoDB GridFS
  • Camel :: Mustache
  • Camel :: MyBatis
  • Camel :: Nats
  • Camel :: Netty
  • Camel :: Netty HTTP
  • Camel :: OAIPMH
  • Camel :: OAuth
  • Camel :: OCSF
  • Camel :: OGNL (deprecated)
  • Camel :: Observability Services
  • Camel :: Olingo2 (Deprecated) :: API
  • Camel :: Olingo2 (Deprecated) :: Component
  • Camel :: Olingo4 (Deprecated) :: API
  • Camel :: Olingo4 (Deprecated) :: Component
  • Camel :: Once
  • Camel :: OpenAPI :: Validator
  • Camel :: OpenApi Java
  • Camel :: OpenSearch Java API Client
  • Camel :: OpenStack
  • Camel :: OpenTelemetry (deprecated)
  • Camel :: Opentelemetry 2
  • Camel :: Opentelemetry Metrics
  • Camel :: OptaPlanner
  • Camel :: PDF
  • Camel :: PLC4X
  • Camel :: PQC
  • Camel :: Paho (deprecated)
  • Camel :: Paho MQTT 5
  • Camel :: Parquet Avro
  • Camel :: PgEvent
  • Camel :: PgReplicationSlot
  • Camel :: Platform HTTP
  • Camel :: Platform HTTP :: Jolokia
  • Camel :: Platform HTTP :: Main
  • Camel :: Platform HTTP :: Vert.x
  • Camel :: Printer
  • Camel :: Protobuf
  • Camel :: PubNub
  • Camel :: Pulsar
  • Camel :: Python
  • Camel :: Quartz
  • Camel :: QuickFIX/J
  • Camel :: REST OpenApi
  • Camel :: RSS
  • Camel :: Reactive Executor :: Tomcat
  • Camel :: Reactive Executor :: Vert.x (deprecated)
  • Camel :: Reactive Streams
  • Camel :: Reactor
  • Camel :: Redis
  • Camel :: Resilience4j
  • Camel :: Resilience4j :: Micrometer
  • Camel :: ResourceResolver GitHub
  • Camel :: RobotFramework
  • Camel :: RocketMQ
  • Camel :: RxJava
  • Camel :: SAP NetWeaver
  • Camel :: SMB
  • Camel :: SMPP
  • Camel :: SNMP
  • Camel :: SOAP
  • Camel :: SQL
  • Camel :: SSH
  • Camel :: SWIFT
  • Camel :: Salesforce
  • Camel :: Salesforce :: CodeGen
  • Camel :: Salesforce :: Maven Plugin
  • Camel :: Saxon
  • Camel :: Schematron
  • Camel :: ServiceNow :: Component
  • Camel :: ServiceNow :: Maven Plugin
  • Camel :: Servlet
  • Camel :: Shell
  • Camel :: Shiro
  • Camel :: Simple JMS
  • Camel :: Simple JMS2
  • Camel :: Slack
  • Camel :: Smooks :: Parent
  • Camel :: SnakeYAML
  • Camel :: Solr
  • Camel :: Splunk (deprecated)
  • Camel :: Splunk HEC
  • Camel :: Spring
  • Camel :: Spring AI :: Chat
  • Camel :: Spring AI :: Embeddings
  • Camel :: Spring AI :: Image
  • Camel :: Spring AI :: Tools
  • Camel :: Spring AI :: Vector Store
  • Camel :: Spring Batch
  • Camel :: Spring Cloud Config
  • Camel :: Spring JDBC
  • Camel :: Spring LDAP
  • Camel :: Spring Main
  • Camel :: Spring RabbitMQ
  • Camel :: Spring Redis
  • Camel :: Spring Security
  • Camel :: Spring Web Services
  • Camel :: Spring XML
  • Camel :: StAX
  • Camel :: Stitch
  • Camel :: Stream
  • Camel :: StringTemplate
  • Camel :: Stripe
  • Camel :: Syslog
  • Camel :: Tahu
  • Camel :: Tar File
  • Camel :: Telegram
  • Camel :: Telemetry :: Dev
  • Camel :: Test :: JUnit5
  • Camel :: Test :: JUnit6
  • Camel :: Test :: Main :: JUnit5
  • Camel :: Test :: Main :: JUnit6
  • Camel :: Test :: Spring :: JUnit5
  • Camel :: Test Infra :: All test services
  • Camel :: Test Infra :: Artemis
  • Camel :: Test Infra :: Core
  • Camel :: Test Infra :: Server Message Block
  • Camel :: Thread Pool Factory :: Vert.x (deprecated)
  • Camel :: Thrift
  • Camel :: Thymeleaf
  • Camel :: Tika
  • Camel :: Twilio
  • Camel :: Twitter
  • Camel :: Undertow
  • Camel :: Undertow Spring Security
  • Camel :: UniVocity Parsers
  • Camel :: Velocity
  • Camel :: Vert.x :: HTTP
  • Camel :: Vert.x :: WebSocket
  • Camel :: Vertx
  • Camel :: Wasm
  • Camel :: Weather
  • Camel :: Web3j
  • Camel :: Webhook
  • Camel :: Whatsapp
  • Camel :: Wordpress
  • Camel :: Workday
  • Camel :: XChange
  • Camel :: XJ
  • Camel :: XML DSL Jaxb :: Test :: Definition
  • Camel :: XML DSL Jaxb :: Test :: Spring
  • Camel :: XML DSL with camel-xml-io
  • Camel :: XML DSL with camel-xml-jaxb
  • Camel :: XML Security
  • Camel :: XMPP
  • Camel :: XSLT Saxon
  • Camel :: YAML DSL :: Validator
  • Camel :: YAML DSL :: Validator Maven Plugin
  • Camel :: Zeebe (deprecated)
  • Camel :: Zendesk
  • Camel :: Zip Deflater
  • Camel :: Zip File
  • Camel :: Zookeeper
  • Camel :: Zookeeper Master
  • Camel :: csimple jOOR (deprecated)
  • Camel :: gRPC
  • Camel :: iCal
  • Camel :: jOOR

⚙️ View full build and test results

@gnodet
gnodet force-pushed the fix/batch16-disruptor-seda-scheduler branch from bae8b08 to ac3d816 Compare July 16, 2026 16:01

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — three well-analyzed flaky test fixes, each targeting the actual root cause.

DisruptorBlockWhenFullTest.syncDelayed() makes the consumer block for the full 100ms
inside onEvent(), keeping the ring buffer full long enough for tryNext() to reliably hit
InsufficientCapacityException. Without it, the async delay returns immediately and the buffer
drains too fast.

SedaBlockWhenFullTestexpectedMinimumMessageCount(QUEUE_SIZE + 1) is the correct
semantic: with blockWhenFull=true, all messages eventually arrive. The exact-count assertion
raced against additional messages flowing through the pipeline after the latch opened.

SchedulerNoPolledMessagesTest — Direct timestamp comparison on already-received exchanges
eliminates the arrives().afterPrevious() race entirely. Verified that MockEndpoint stores
RECEIVED_TIMESTAMP as new Date() (camel-mock MockEndpoint.java:1848), so the
getProperty(Exchange.RECEIVED_TIMESTAMP, Date.class) access is safe.

Claude Code on behalf of gnodet

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice batch — all three fixes target the actual mechanism of the flakiness rather than widening timeout windows. Clean work.

What's good

  • Root cause depth is outstanding. Each fix targets the specific mechanism: async delay semantics in Disruptor, exact-vs-minimum count race in SEDA, and the arrives() API race in Scheduler. The Develocity data provides empirical backing.
  • The SchedulerNoPolledMessagesTest rewrite is a genuine upgrade. After the prior widening attempt (commit 3009c0da4c7e), this PR takes the fundamentally better approach: wait for messages, then examine timestamps on a stable list. Eliminates the entire class of race.
  • Comment quality is excellent. Each change explains why, not just what.

Minor suggestions

SchedulerNoPolledMessagesTest — dropped upper bound on backoff gap
core/camel-core/src/test/java/org/apache/camel/component/scheduler/SchedulerNoPolledMessagesTest.java

The old code checked between(200, 5000) for the backoff gap. The new code only checks gap12 >= 200 (lower bound only). Dropping the upper bound is the right call for CI stability, but if you want to catch a hypothetical regression where the scheduler ignores the backoff entirely and waits far too long, a generous upper bound could help:

assertTrue(gap12 <= 10000,
        "Backoff gap should not exceed 10s (expected ~1000 ms), was " + gap12 + " ms");

Truly optional — the test's purpose is verifying backoff kicks in, not capping it.

Verified claims

  • delay() defaults to async: DelayProcessorSupport.java:44private boolean asyncDelayed = true
  • Exchange.RECEIVED_TIMESTAMP exists and is set by MockEndpoint
  • ✅ No Thread.sleep() introduced
  • MockEndpoint.assertIsSatisfied(context, 30, TimeUnit.SECONDS) used correctly per project guidelines
  • ✅ All new imports are used; no unused imports

CI status

Two jobs failed (build (17, false) and build (25, false)) — both on camel-smb integration tests, unrelated to this PR.

Checklist

Check Status
Tests ✅ This PR IS the test fix
Thread.sleep() ✅ None introduced
MockEndpoint usage ✅ Correct per guidelines
Documentation N/A (test-only)
Commit convention
Public API / backward compat N/A (test-only)

Reviewed with Claude Code on behalf of gnodet. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.

@oscerd oscerd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — all three attack the actual race rather than widening a window:

  • DisruptorBlockWhenFullTest: .syncDelayed() makes the delay block on the event-loop thread so the ring buffer stays full and InsufficientCapacityException fires reliably (delay() is async by default).
  • SedaBlockWhenFullTest: expectedMessageCountexpectedMinimumMessageCount — the correct semantic for blockWhenFull=true (all messages eventually arrive), removing the exact-count-vs-latch race.
  • SchedulerNoPolledMessagesTest: replaces the fragile arrives().afterPrevious() with a direct RECEIVED_TIMESTAMP comparison on already-received exchanges — the cleanest of the batch.

No Thread.sleep added. The red build (25) is an unrelated camel-smb Testcontainers IT flake — camel-smb is only pulled into the reactor as a transitive dependent of the modified camel-core (which itself built and tested fine), and build (17) was cancelled by matrix fail-fast, not an independent failure. A re-run should clear it. (Minor: the SchedulerNoPolledMessagesTest change drops the old upper bound on the backoff gap, which you already flagged as optional in your own note.)

Reviewed with Claude Code on behalf of Andrea Cosentino. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.

gnodet and others added 3 commits July 17, 2026 11:50
The delay() EIP defaults to async mode, so the consumer's onEvent()
returns in microseconds — the ring buffer drains nearly as fast as
the producer fills it. On a loaded CI, the buffer may never be full
at the instant tryNext() is called, preventing the expected exception.

Add syncDelayed() so the consumer blocks for the full 100ms delay
inside onEvent(), keeping the ring buffer full long enough for the
producer to reliably hit InsufficientCapacityException.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
With blockWhenFull=true and async sends, all messages eventually
arrive at the mock (they block and wait for queue space rather
than failing). The exact-count assertion (expectedMessageCount)
races: after the latch opens at count N, additional messages can
arrive before assertEquals runs, causing "expected N but was N+k".

Switch to expectedMinimumMessageCount which uses a >= check —
immune to additional messages arriving after the latch opens.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The arrives().afterPrevious() API has a subtle race: when computing
"after previous", it actually compares with the NEXT message's
timestamp (if one has arrived), not the previous one. A 4th message
arriving ~100ms after the 3rd violates the 200ms lower bound that
was intended for the backoff gap between messages 1 and 2.

Replace the fragile MockEndpoint timing API with direct timestamp
comparison on already-received (immutable) exchanges after
assertIsSatisfied completes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@davsclaus
davsclaus force-pushed the fix/batch16-disruptor-seda-scheduler branch from ac3d816 to cd9a7a6 Compare July 17, 2026 09:50

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code on behalf of gnodet

Re-review after new commits — all three fixes look solid.

DisruptorBlockWhenFullTest

.syncDelayed() is the right fix. Without it, the default async delay causes messages to pass through the ring buffer too quickly, so the buffer may not be full when the test expects InsufficientCapacityException. With .syncDelayed(), the consumer blocks for the full delay period, keeping the slot occupied. The comment explaining the rationale is a nice touch.

SchedulerNoPolledMessagesTest

Excellent analysis of the arrives().afterPrevious() race condition. The direct timestamp comparison using Exchange.RECEIVED_TIMESTAMP is more reliable and avoids the subtle issue where a 4th message arriving ~100ms after the 3rd violates the lower bound intended for the backoff gap (msg 1→2). The wide timing windows (gap01 ≤ 2000ms, gap12 ≥ 200ms) are appropriately generous for CI environments.

SedaBlockWhenFullTest

expectedMinimumMessageCount(QUEUE_SIZE + 1) is correct. With blockWhenFull=true and async sends, all messages eventually arrive — they block and wait for queue space rather than failing. An exact-count assertion races against the remaining messages still flowing through the 130ms delay pipeline. Good explanatory comment.

All changes are well-documented with comments explaining the reasoning. LGTM ✅

@davsclaus davsclaus added this to the 4.22.0 milestone Jul 18, 2026
@davsclaus
davsclaus merged commit a7ee805 into apache:main Jul 18, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants