Skip to content

CAMEL-24583: camel-master - do not start the delegated consumer after leadership is lost (CAMEL-24584) - #26028

Merged
davsclaus merged 2 commits into
apache:mainfrom
henrik242:camel-24583-master-leadership-race
Sep 2, 2026
Merged

CAMEL-24583: camel-master - do not start the delegated consumer after leadership is lost (CAMEL-24584)#26028
davsclaus merged 2 commits into
apache:mainfrom
henrik242:camel-24583-master-leadership-race

Conversation

@henrik242

@henrik242 henrik242 commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes CAMEL-24583 and CAMEL-24584.

Problem

MasterConsumer starts the delegated consumer from a BackgroundTask scheduled one second after the
leadership-taken event. A leadership-lost event arriving inside that window was dropped, because the
listener only dispatched it else if (delegatedConsumer != null) and that field is still null while the
start is pending. Nothing cancelled the pending task, so it started the consumer on a node that was no
longer the leader, and no further event was coming to stop it.

Seen in production with a Google Pub/Sub delegate behind KubernetesClusterService: a three second
membership flap left subscribers running on the follower pod, feeding routes whose error handlers had been
stopped, so messages were dropped rather than redelivered to the leader.

Changes

CAMEL-24584 - camel-support (first commit)

BackgroundTask.schedule cancels the future it creates once the task is completed or exhausted. It
previously stayed armed and the task kept being re-run as a no-op for the life of the executor.

CAMEL-24583 - camel-master (second commit)

  • Leadership is tracked in state guarded by the consumer lock, and the scheduled task re-checks it before
    starting the delegate.
  • The listener reads the leadership under that lock and dispatches the lost event unconditionally, so it
    cancels a pending start instead of being dropped.
  • The delegate is created and started off the lock, then published only if the leadership still holds,
    otherwise it is stopped again.
  • delegatedConsumer is published only after a successful start, so a failed start no longer makes every
    later leadership term a no-op.
  • backOffMaxAttempts now bounds the attempts. The task also carried the five second default duration of
    its budget, which ended it before the second attempt at any backOffDelay of five seconds or more.

Testing

MasterConsumerLeadershipTest uses a fake cluster view whose leadership can be flapped on demand, and
covers the pending start, a loss while the start is in progress, a flap after a successful start, repeated
taken events, cancellation on stop, exhausted-retry recovery, and the configured attempt count. Two tests
added to BackgroundTaskTest. All of them were checked against unpatched main and fail there.

Known pre-existing issues

Found while working on this. None are introduced here and none are fixed here.

  • Lock ordering between the cluster view and the consumer. doStop holds the consumer's
    BaseService lock and then needs the view's write lock via removeEventListener, while
    AbstractCamelClusterView dispatches events holding its read lock and then needs the consumer lock.
    The inversion predates this change, but dispatching the lost event unconditionally widens exposure to
    it. Mitigated here by an unlocked isRunAllowed() fast path in the listener, by running the delegated
    start off the lock, and by cancelling the pending task before the listener is removed. The constraint
    is now written down in doStop so it survives the merge. It still deserves a follow-up JIRA, since a
    proper fix means moving the leadership state off BaseService.lock.
  • TaskManagerRegistry entries leak when a future is cancelled by the caller. runTaskWrapper only
    unregisters from inside a later run, which cannot happen once the future is cancelled. This affects
    camel-sjms today and camel-master after this change. Better fixed by a BackgroundTask cancel
    operation that also deregisters.
  • A leader that exhausts its start attempts consumes nothing until the leadership changes again.
    This change makes that state recoverable and logs it at ERROR, but adds no retry trigger.

One note on the diff rather than a pre-existing issue: the delegated consumer is created once per task and
reused across its attempts, so addStartupListener and the resume strategy are wired once. A consumer that
failed to start is deliberately not shut down, since DefaultConsumer.doShutdown would also shut down the
route's processor, which the next attempt still needs.

@henrik242 henrik242 changed the title CAMEL-24583: camel-master - do not start the delegated consumer after leadership is lost CAMEL-24583: camel-master - do not start the delegated consumer after leadership is lost (CAMEL-24584) Sep 2, 2026
@atiaomar1978-hub

Copy link
Copy Markdown
Contributor

PR review summary

AI-generated review on behalf of atiaomar1978-hub

Verdict: Approve in principle — this is a well-scoped, production-motivated fix with strong tests. The two-commit split (camel-support first, then camel-master) is the right dependency order.

What works well

  • Root cause addressed directly: Leadership-lost during the 1s pending start window is no longer dropped; the scheduled task is cancelled and leadershipTaken is re-checked before starting the delegated consumer.
  • CAMEL-24584 is a necessary foundation: BackgroundTask auto-unschedule makes isStartPending() meaningful and stops lifetime no-op rescheduling.
  • Failed-start recovery: Publishing delegatedConsumer only after a successful startService() fixes the “stuck leader that never retries” failure mode — covered by testConsumerStartsAfterLeadershipIsTakenAgainWhenAnEarlierStartFailed.
  • Operational visibility: ERROR log when backoff is exhausted while still holding leadership is valuable for on-call.
  • Tests: MasterConsumerLeadershipTest is an excellent reproducer harness; the PR author’s note about verifying failures on unpatched main adds confidence.

Inline notes (non-blocking follow-ups)

  1. Partial attempt cleanup — if createConsumer() succeeded but leadership is lost before publish, attempt may hold an unstarted consumer that is not shut down (see inline on MasterConsumer).
  2. Upgrade guide — consider a camel-master entry alongside the camel-support note for operators who hit the K8s/Pub/Sub follower-consumer symptom.
  3. Pre-existing lock ordering — agree with the PR description that cluster-view ↔ consumer lock inversion remains a separate follow-up.

Testing / CI

CI had not reported checks on the branch at review time. Locally the described matrix (7 new master tests + 2 BackgroundTask tests) is appropriate for this change set.

Thanks @henrik242 for the thorough PR description and the transparent “known pre-existing issues” section — that made review much easier.

@davsclaus davsclaus 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.

Reviewed against this project's rule files (build/test/style conventions, commit/PR conventions, AI-attribution rules) and by building + running the changed modules in an isolated worktree: camel-support (BackgroundTaskTest, 8/8 pass) and camel-master (27/27 pass, including the new MasterConsumerLeadershipTest run 3x with no flakiness). The fix itself is well-reasoned and well-tested — I traced the lock.lockInterruptibly() + cancelLeaderTask(true) design in startDelegatedConsumer/doStop and didn't find a correctness bug in the leadership state machine.

Two non-blocking findings:

  1. Missing AI co-authorship trailer. The PR description states "Claude Code on behalf of henrik242", but the single commit (f7cea19c2b) has no Co-authored-by trailer. Per this project's AI-agent attribution rule, AI-assisted commits should carry one.
  2. PR description vs. actual commit history. The description explains two ordered commits (camel-support first, camel-master second) with a specific rationale for that order ("the reverse order would leave a failing test at the intermediate commit"). The PR actually contains a single squashed commit touching both modules. Not wrong, just worth reconciling so a reviewer trying to verify the described ordering isn't misled.

One inline note below on a lock-ordering point the author already flagged transparently in "Notes for reviewers" — confirmed by reading AbstractCamelClusterView/BaseService, recommending a follow-up JIRA rather than blocking this PR on it.

This review does not replace CodeRabbit/Sourcery/SonarCloud or a dedicated concurrency review.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

@github-actions

github-actions Bot commented Sep 2, 2026

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.

@Croway Croway 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.

Thanks for the PR, the direction (never start the delegate after leadership was lost, retry on the next term) is the right one. Reviewing the locking changes though, there are three problems I think need to be addressed before this can go in. Details inline.

  1. Lock-order inversion between BaseService.lock and the cluster view's StampedLock that can deadlock a leadership event overlapping stop().
  2. The delegated consumer is now created and started while holding BaseService.lock, which blocks stop/suspend/resume and every cluster event for the duration of a slow start.
  3. The new "Giving up after N attempts" log never fires with default settings, because the iteration/time budget exhausts after ~5 s (one attempt), so backOffMaxAttempts is effectively ignored.

Claude Code on behalf of Croway

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-master
  • core/camel-core
  • core/camel-support
  • docs

ℹ️ Dependent modules were not tested because the total number of affected modules exceeded the threshold (50). Use the test-dependents label to force testing all dependents.


🔬 Scalpel shadow comparison — Scalpel: 563 tested, 26 compile-only — current: 562 all tested

Maveniverse Scalpel detected 589 affected modules (current approach: 562).

⚠️ Modules only in Scalpel (27)
  • 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

Skip-tests mode would test 563 modules (4 direct + 559 downstream), skip tests for 26 (generated code, meta-modules)

Modules Scalpel would test (563)
  • archetypes
  • camel-a2a
  • camel-activemq
  • camel-activemq6
  • camel-ai-observability
  • camel-ai-observability-api
  • camel-ai-parent
  • camel-ai-resource
  • camel-ai-tool
  • camel-alibaba-common
  • camel-alibaba-eventbridge
  • camel-alibaba-fc
  • camel-alibaba-kms
  • camel-alibaba-mns
  • camel-alibaba-oss
  • camel-alibaba-ots
  • camel-alibaba-parent
  • camel-alibaba-sls
  • camel-alibaba-sms
  • camel-amqp
  • camel-api-component-maven-plugin
  • camel-arangodb
  • camel-archetype-api-component
  • camel-archetype-component
  • camel-archetype-dataformat
  • camel-archetype-java
  • camel-archetype-main
  • camel-as2
  • camel-as2-api
  • camel-as2-parent
  • camel-asn1
  • camel-asterisk
  • camel-atmosphere-websocket
  • camel-atom
  • camel-attachments
  • camel-avro
  • camel-avro-rpc
  • camel-avro-rpc-jetty
  • camel-avro-rpc-parent
  • camel-avro-rpc-spi
  • camel-aws-bedrock
  • camel-aws-cloudtrail
  • camel-aws-common
  • camel-aws-config
  • camel-aws-parameter-store
  • camel-aws-parent
  • camel-aws-secrets-manager
  • camel-aws-security-hub
  • camel-aws2-athena
  • camel-aws2-comprehend
  • camel-aws2-cw
  • camel-aws2-ddb
  • camel-aws2-ec2
  • camel-aws2-ecs
  • camel-aws2-eks
  • camel-aws2-eventbridge
  • camel-aws2-iam
  • camel-aws2-kinesis
  • camel-aws2-kms
  • camel-aws2-lambda
  • camel-aws2-mq
  • camel-aws2-msk
  • camel-aws2-polly
  • camel-aws2-redshift
  • camel-aws2-rekognition
  • camel-aws2-s3
  • camel-aws2-s3-vectors
  • camel-aws2-ses
  • camel-aws2-sns
  • camel-aws2-sqs
  • camel-aws2-step-functions
  • camel-aws2-sts
  • camel-aws2-textract
  • camel-aws2-timestream
  • camel-aws2-transcribe
  • camel-aws2-translate
  • camel-azure-common
  • camel-azure-cosmosdb
  • camel-azure-eventgrid
  • camel-azure-eventhubs
  • camel-azure-files
  • camel-azure-functions
  • camel-azure-key-vault
  • camel-azure-parent
  • camel-azure-schema-registry
  • camel-azure-servicebus
  • camel-azure-storage-blob
  • camel-azure-storage-datalake
  • camel-azure-storage-queue
  • camel-barcode
  • camel-base
  • camel-base-engine
  • camel-base64
  • camel-bean
  • camel-bean-validator
  • camel-beanio
  • camel-bindy
  • camel-bonita
  • camel-box
  • camel-box-api
  • camel-box-parent
  • camel-braintree
  • camel-browse
  • camel-caffeine
  • camel-camunda
  • camel-cassandraql
  • camel-catalog-common
  • camel-cbor
  • camel-chatscript
  • camel-chunk
  • camel-cli-connector
  • camel-cli-debug
  • camel-clickhouse
  • camel-clickup
  • camel-cloudevents
  • camel-cluster
  • camel-cm-sms
  • camel-coap
  • camel-cometd
  • camel-console
  • camel-consul
  • camel-controlbus
  • camel-core
  • camel-core-all
  • camel-core-engine
  • camel-core-languages
  • camel-core-model
  • camel-core-processor
  • camel-core-reifier
  • camel-core-xml
  • camel-couchbase
  • camel-couchdb
  • camel-cron
  • camel-crypto
  • camel-crypto-pgp
  • camel-csv
  • camel-cxf-common
  • camel-cxf-parent
  • camel-cxf-rest
  • camel-cxf-soap
  • camel-cxf-spring-common
  • camel-cxf-spring-rest
  • camel-cxf-spring-soap
  • camel-cxf-spring-transport
  • camel-cxf-transport
  • camel-cyberark-vault
  • camel-dapr
  • camel-dataformat
  • camel-dataset
  • camel-datasonnet
  • camel-dataweave
  • camel-debezium-common
  • camel-debezium-common-parent
  • camel-debezium-db2
  • camel-debezium-maven-plugin
  • camel-debezium-mongodb
  • camel-debezium-mysql
  • camel-debezium-oracle
  • camel-debezium-parent
  • camel-debezium-postgres
  • camel-debezium-sqlserver
  • camel-debug
  • camel-dfdl
  • camel-dhis2
  • camel-dhis2-api
  • camel-dhis2-parent
  • camel-diagram
  • camel-direct
  • camel-disruptor
  • camel-djl
  • camel-dns
  • camel-docker
  • camel-docling
  • camel-drill
  • camel-dropbox
  • camel-dsl-modeline
  • camel-dsl-support
  • camel-duckdb
  • camel-dynamic-router
  • camel-ehcache
  • camel-elasticsearch
  • camel-elasticsearch-rest-client
  • camel-event
  • camel-exec
  • camel-fastjson
  • camel-fhir
  • camel-fhir-api
  • camel-fhir-parent
  • camel-file
  • camel-file-watch
  • camel-flatpack
  • camel-flink
  • camel-flowable
  • camel-fop
  • camel-fory
  • camel-freemarker
  • camel-ftp
  • camel-ftp-common
  • 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-parent
  • 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-vertexai
  • camel-google-vision
  • camel-graphql
  • camel-grok
  • camel-groovy
  • camel-grpc
  • camel-gson
  • camel-hashicorp-vault
  • camel-hazelcast
  • camel-health
  • camel-hivemq
  • camel-hl7
  • camel-http
  • camel-http-base
  • camel-http-common
  • camel-huawei-parent
  • camel-huaweicloud-common
  • camel-huaweicloud-dms
  • camel-huaweicloud-frs
  • camel-huaweicloud-functiongraph
  • camel-huaweicloud-iam
  • camel-huaweicloud-imagerecognition
  • camel-huaweicloud-obs
  • camel-huaweicloud-smn
  • camel-huggingface
  • camel-ibm-cos
  • camel-ibm-parent
  • 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-ical
  • camel-iggy
  • camel-ignite
  • camel-infinispan
  • camel-infinispan-common
  • camel-infinispan-embedded
  • camel-infinispan-parent
  • camel-influxdb
  • camel-influxdb2
  • camel-iso8583
  • camel-jackson
  • camel-jackson-avro
  • camel-jackson-protobuf
  • camel-jackson3
  • camel-jackson3-avro
  • camel-jackson3-protobuf
  • camel-jackson3xml
  • camel-jacksonxml
  • camel-jactl
  • camel-jandex
  • camel-jasypt
  • camel-java-io
  • camel-java-joor-dsl
  • camel-javascript
  • 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-jcache
  • camel-jcr
  • camel-jdbc
  • camel-jetty
  • camel-jetty-common
  • camel-jfr
  • camel-jgroups
  • camel-jgroups-raft
  • camel-jira
  • camel-jms
  • camel-jmx
  • camel-jolt
  • camel-jooq
  • camel-joor
  • camel-jpa
  • camel-jq
  • camel-jsch
  • camel-jslt
  • camel-json-validator
  • camel-jsonapi
  • camel-jsonata
  • camel-jsonb
  • camel-jsonpath
  • camel-jsoup
  • camel-jt400
  • camel-jta
  • camel-jte
  • camel-kafka
  • camel-kamelet
  • camel-kamelet-main-support
  • camel-keycloak
  • camel-knative
  • camel-knative-api
  • camel-knative-http
  • camel-knative-parent
  • camel-kserve
  • camel-kubernetes
  • camel-kudu
  • camel-langchain4j-agent
  • camel-langchain4j-agent-api
  • camel-langchain4j-chat
  • camel-langchain4j-core
  • camel-langchain4j-embeddings
  • camel-langchain4j-embeddingstore
  • camel-langchain4j-embeddingstore-api
  • camel-langchain4j-tokenizer
  • camel-langchain4j-web-search
  • camel-language
  • camel-launcher-container
  • camel-ldap
  • camel-ldif
  • camel-log
  • camel-lra
  • camel-lucene
  • camel-lumberjack
  • camel-lzf
  • camel-mail
  • camel-mail-microsoft-oauth
  • camel-main
  • camel-management
  • camel-mapstruct
  • camel-master
  • camel-maven-plugin
  • camel-mcp-server
  • camel-mcp-server-api
  • camel-mdc
  • camel-metrics
  • camel-micrometer
  • camel-micrometer-observability
  • camel-micrometer-prometheus
  • camel-microprofile-config
  • camel-microprofile-fault-tolerance
  • camel-microprofile-health
  • camel-microprofile-parent
  • camel-milo
  • camel-milvus
  • camel-mina
  • camel-mina-sftp
  • camel-minio
  • camel-mllp
  • camel-mock
  • camel-mongodb
  • camel-mongodb-gridfs
  • camel-mustache
  • camel-mvel
  • camel-mybatis
  • camel-nats
  • camel-neo4j
  • camel-netty
  • camel-netty-http
  • camel-oaipmh
  • camel-oauth
  • camel-observability-services
  • camel-observation
  • camel-ocsf
  • camel-ognl
  • camel-olingo2
  • camel-olingo2-api
  • camel-olingo2-parent
  • camel-olingo4
  • camel-olingo4-api
  • camel-olingo4-parent
  • camel-once
  • camel-openai
  • camel-openapi-java
  • camel-openapi-rest-dsl-generator
  • camel-openapi-validator
  • camel-opensearch
  • camel-openstack
  • camel-opentelemetry
  • camel-opentelemetry-metrics
  • camel-opentelemetry2
  • camel-optaplanner
  • camel-paho
  • camel-paho-mqtt5
  • camel-parquet-avro
  • camel-pdf
  • camel-pg-replication-slot
  • camel-pgevent
  • camel-pgvector
  • camel-pinecone
  • camel-platform-http
  • camel-platform-http-jolokia
  • camel-platform-http-main
  • camel-platform-http-vertx
  • camel-plc4x
  • camel-pqc
  • camel-printer
  • camel-protobuf
  • camel-pubnub
  • camel-pulsar
  • camel-python
  • camel-python3
  • camel-qdrant
  • camel-quartz
  • camel-quickfix
  • camel-quickjs
  • camel-reactive-streams
  • camel-reactor
  • camel-redis
  • camel-ref
  • camel-resilience4j
  • camel-resilience4j-micrometer
  • camel-resourceresolver-github
  • camel-rest
  • camel-rest-openapi
  • camel-rest-postman
  • camel-restdsl-openapi-plugin
  • camel-robotframework
  • camel-rocketmq
  • camel-rss
  • camel-rxjava
  • camel-saga
  • camel-salesforce
  • camel-salesforce-codegen
  • camel-salesforce-maven-plugin
  • camel-salesforce-parent
  • camel-sap-netweaver
  • camel-saxon
  • camel-scheduler
  • camel-schematron
  • camel-seda
  • camel-servicenow
  • camel-servicenow-maven-plugin
  • camel-servicenow-parent
  • camel-servlet
  • camel-shell
  • camel-shiro
  • camel-sjms
  • camel-sjms2
  • camel-slack
  • camel-smb
  • camel-smooks
  • camel-smpp
  • camel-snakeyaml
  • camel-snmp
  • camel-soap
  • camel-solr
  • camel-spiffe
  • camel-splunk-hec
  • camel-spring
  • camel-spring-ai-chat
  • camel-spring-ai-embeddings
  • camel-spring-ai-image
  • camel-spring-ai-parent
  • camel-spring-ai-vector-store
  • camel-spring-batch
  • camel-spring-cloud-config
  • camel-spring-jdbc
  • camel-spring-ldap
  • camel-spring-main
  • camel-spring-parent
  • camel-spring-rabbitmq
  • camel-spring-redis
  • camel-spring-security
  • camel-spring-ws
  • camel-spring-xml
  • camel-sql
  • camel-ssh
  • camel-state-store
  • camel-state-store-parent
  • camel-stax
  • camel-stitch
  • camel-stream
  • camel-streamcaching-test
  • camel-stringtemplate
  • camel-stripe
  • camel-stub
  • camel-support
  • camel-swift
  • camel-syslog
  • camel-tahu
  • camel-tarfile
  • camel-telegram
  • camel-telemetry
  • camel-telemetry-dev
  • camel-tensorflow-serving
  • camel-test-infra-all
  • camel-test-infra-artemis
  • camel-test-infra-cli
  • camel-test-infra-core
  • camel-test-infra-smb
  • camel-test-junit5
  • camel-test-junit6
  • camel-test-main-junit5
  • camel-test-main-junit6
  • camel-test-parent
  • camel-test-spring-junit5
  • camel-test-spring-junit6
  • camel-thrift
  • camel-thymeleaf
  • camel-tika
  • camel-timer
  • camel-tooling-maven
  • camel-toon
  • camel-tracing
  • camel-twilio
  • camel-twitter
  • camel-ubl
  • camel-undertow
  • camel-undertow-spring-security
  • camel-univocity-parsers
  • camel-validator
  • camel-velocity
  • camel-vertx
  • camel-vertx-common
  • camel-vertx-http
  • camel-vertx-parent
  • camel-vertx-websocket
  • camel-wal
  • camel-wasm
  • camel-weather
  • camel-weaviate
  • camel-web3j
  • camel-webhook
  • camel-whatsapp
  • camel-wordpress
  • camel-workday
  • camel-xchange
  • camel-xj
  • camel-xml-io
  • camel-xml-io-dsl
  • camel-xml-jaxb
  • camel-xml-jaxb-dsl
  • camel-xml-jaxb-dsl-test-definition
  • camel-xml-jaxb-dsl-test-spring
  • camel-xml-jaxp
  • camel-xmlsecurity
  • camel-xmpp
  • camel-xpath
  • camel-xslt
  • camel-xslt-saxon
  • camel-yaml-dsl-common
  • camel-yaml-dsl-validator
  • camel-yaml-dsl-validator-maven-plugin
  • camel-yaml-io
  • camel-zendesk
  • camel-zip-deflater
  • camel-zipfile
  • camel-zookeeper
  • camel-zookeeper-master
  • components
  • docs
Modules with tests skipped (26)
  • 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
  • dummy-component

ℹ️ 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
Build reactor — dependencies compiled but only changed modules were tested (4 modules)
  • Camel :: Core
  • Camel :: Docs
  • Camel :: Master
  • Camel :: Support

⚙️ View full build and test results

@henrik242
henrik242 force-pushed the camel-24583-master-leadership-race branch from f7cea19 to 9c85639 Compare September 2, 2026 15:30
…ompleted or exhausted

The future from schedule() was never cancelled, so a finished task kept
being re-run as a no-op for the life of the executor. A caller cannot fix
the exhausted case itself, as the supplier is never invoked again.
… leadership is lost

Also makes backOffMaxAttempts bound the start attempts, which the default
5s time budget of the task ended before the second attempt.
@henrik242
henrik242 force-pushed the camel-24583-master-leadership-race branch from 9c85639 to e53dc94 Compare September 2, 2026 16:12
@davsclaus
davsclaus requested a review from Croway September 2, 2026 16:54

@davsclaus davsclaus 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.

Approving. I re-reviewed the current diff against this project's rules (build/test/style, commit/PR conventions, AI-attribution) and against the earlier CHANGES_REQUESTED review, and traced the leadership state machine plus the referenced APIs (BaseService.lock = ReentrantLock, AbstractCamelClusterView = StampedLock, withUnlimitedDuration, ExecutorServiceManager.shutdown with awaitTermination=0).

The three previously requested changes are all addressed in the current diff:

  1. Start no longer runs under BaseService.lockstartDelegatedConsumer claims under the lock, releases it, runs createConsumer()/startService() off-lock, then re-acquires to publish delegatedConsumer (and stops the freshly-started consumer if leadership was lost in the meantime). Exactly the shape suggested.
  2. backOffMaxAttempts is now effective.withUnlimitedDuration() means the default 5s budget no longer ends the task before the second attempt; the give-up ERROR is guarded by maxAttempts > 0; testAllConfiguredStartAttemptsAreMade covers it at default-scale timings.
  3. Lock-order inversion (view StampedLock vs consumer lock) — mitigated via the unlocked isRunAllowed() fast path, cancelling the pending task before removeEventListener in doStop, and moving the start off the lock.

One residual, non-blocking note: the lock-order inversion is mitigated but not fully eliminated — a narrow window remains where the event thread passes the fast isRunAllowed() check, then stop() transitions to STOPPING and holds lock while removeEventListener needs the view write lock, and the event thread parks on lock while holding the view read lock. This is genuinely pre-existing (the old "taken" path already re-entered the consumer lock from under the view read lock) and is transparently disclosed in the PR body and an inline comment, with a follow-up JIRA proposed. A complete fix means moving leadership state off BaseService.lock, which is out of scope here — reasonable to track separately.

Everything else checks out: CI green (build 17 & 25); strong, infra-free test coverage of the pending/in-progress/flap/stop-cancel/exhausted-recovery/attempt-count cases; no Thread.sleep (awaitility + latches); JUnit assertions correctly match the camel-master module convention; upgrade-guide entries present for both camel-support and camel-master behavior changes; commit messages follow CAMEL-XXXX: and the branch is the two ordered commits as described.

This review does not replace CodeRabbit/Sourcery/SonarCloud or a dedicated concurrency review.

This review was generated by an AI agent on behalf of davsclaus and may contain inaccuracies. Please verify all suggestions before applying.

@davsclaus davsclaus added this to the 4.23.0 milestone Sep 2, 2026
@davsclaus davsclaus added the bug Something isn't working label Sep 2, 2026
@davsclaus
davsclaus merged commit f899b39 into apache:main Sep 2, 2026
6 checks passed
davsclaus added a commit that referenced this pull request Sep 3, 2026
… leadership is lost (CAMEL-24584) (#26052)

MasterConsumer started the delegated consumer from a BackgroundTask scheduled after the
leadership-taken event. A leadership-lost event arriving during that window was dropped
because delegatedConsumer was still null, leaving the consumer running on a non-leader node.
Leadership is now tracked under the consumer lock; the scheduled task re-checks it before
starting, the lost event is dispatched unconditionally to cancel a pending start, the delegate
is created off the lock and published only if leadership still holds, and delegatedConsumer is
published only after a successful start. backOffMaxAttempts now correctly bounds the attempts.

Also fixes CAMEL-24584: BackgroundTask.schedule now cancels its repeating schedule once the
task has completed or run out of budget, instead of re-running as a no-op for the life of the
executor.

Closes #26028

(cherry picked from commit f899b39)

Co-authored-by: henrik242 <henrik242@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working components core docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants