Skip to content

CAMEL-24357: camel-aws2-s3-vectors - consumer returns no results (topK=0), ignores delay, and can lose vectors - #25369

Merged
davsclaus merged 1 commit into
apache:mainfrom
oscerd:fix/CAMEL-24357
Aug 6, 2026
Merged

CAMEL-24357: camel-aws2-s3-vectors - consumer returns no results (topK=0), ignores delay, and can lose vectors#25369
davsclaus merged 1 commit into
apache:mainfrom
oscerd:fix/CAMEL-24357

Conversation

@oscerd

@oscerd oscerd commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

CAMEL-24357: camel-aws2-s3-vectors — consumer was non-functional and could lose vectors

The aws2-s3-vectors consumer had several defects, all rooted in consumer options that shadow the base scheduled-poll options.

1. Consumer always sent topK(0) — returned nothing (primary, HIGH)

AWS2S3VectorsConsumer.poll() built the query with topK(Math.min(getMaxMessagesPerPoll(), getConfiguration().getTopK())). getMaxMessagesPerPoll() is the base ScheduledBatchPollingConsumer field, which defaults to 0 and was never wired — AWS2S3VectorsEndpoint.createConsumer() only called configureConsumer(consumer), never setMaxMessagesPerPoll(..) (unlike AWS2S3Endpoint). So the expression was Math.min(0, topK) = 0 and every poll sent topK(0), which AWS S3 Vectors rejects (topK >= 1). The consumer delivered zero messages out of the box.

Fix: wire setMaxMessagesPerPoll from the configuration in createConsumer, and resolve topK so that a non-positive maxMessagesPerPoll (the "unlimited" default) means "use the configured topK" instead of capping to zero.

2. delay option was ignored

delay is declared on the configuration, so ?delay= bound to configuration.setDelay(..) — a value the consumer never read; the real poll interval came from the inherited ScheduledPollEndpoint. A user setting ?delay=60000 was silently ignored.

Fix: propagate configuration.getDelay() to the consumer's scheduler in createConsumer (same place maxMessagesPerPoll is now wired).

3. Vectors marked processed before routing → event loss on failure

poll() added each vector id to processedVectorIds at enqueue time, before the exchange was routed. If routing later failed, the vector stayed in the index but was in the de-dup set, so the fixed similarity query skipped it forever. The set was also cleared only on stop (unbounded growth).

Fix: only track processedVectorIds when deleteAfterRead=false (deletion already prevents re-delivery, so the set no longer grows in that mode), and drop the id again on failure (VectorDedupSynchronization.onFailure) so a failed exchange is retried on a later poll.

Tests

New AWS2S3VectorsConsumerTest (Mockito): consumerSendsPositiveTopK captures the QueryVectorsRequest and asserts topK is >= 1 (fails against the old code), and delayOptionDrivesTheConsumerPollInterval asserts the configured delay reaches the consumer's scheduler. Existing producer tests still pass; full reactor build is green.

No public API change. assertj-core added as a test dependency (project-standard). Targets main (4.22.0) and camel-4.18.x (the module was added in 4.17.0; it does not exist on 4.14.x).


Claude Code on behalf of oscerd

…ors delay, and no longer loses vectors on failure

The aws2-s3-vectors consumer had several defects rooted in consumer options that
shadow the base scheduled-poll options:

- poll() sent topK(Math.min(getMaxMessagesPerPoll(), topK)) where the base
  maxMessagesPerPoll field was never wired (default 0), so topK(0) was sent and
  AWS returned nothing. maxMessagesPerPoll is now wired from the configuration in
  createConsumer and topK treats a non-positive cap as "unlimited".
- the delay option bound to a configuration field the consumer never read; it is
  now propagated to the consumer's scheduler.
- vectors were marked processed before routing, so a failed exchange was skipped
  forever; the de-dup set is now only populated when deleteAfterRead=false and an
  id is dropped again on failure so the vector can be retried on a later poll.

Adds AWS2S3VectorsConsumerTest covering the topK and delay fixes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
@oscerd
oscerd requested review from Croway and davsclaus August 6, 2026 05:10
@oscerd oscerd added the bug Something isn't working label Aug 6, 2026
@oscerd oscerd added this to the 4.22.0 milestone Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 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.

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

Solid bugfix PR — all three issues are well-analyzed and the fixes are correct.

Verified:

  • topK(0) bug: resolveTopK() correctly treats non-positive maxMessagesPerPoll as "unlimited" instead of capping to 0. Matches the aws2-s3 endpoint pattern.
  • delay shadowing: the @UriParam on the configuration captures the value before configureConsumer can map it, so explicit propagation is needed and correct.
  • De-dup logic: clean separation — deletion prevents re-delivery so the set is only needed when deleteAfterRead=false. The VectorDedupSynchronization.onFailure correctly drops the id on failure for retry.

Tests follow project conventions (AssertJ, package-private visibility, descriptive names) and directly exercise the bug conditions.

One minor non-blocking observation noted inline.

Note: this review covers project rules and conventions. It does not replace specialized AI review tools (CodeRabbit, Sourcery) or static analysis (SonarCloud).

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

// Track for de-duplication only when we are not deleting (a deleted vector cannot be
// returned again). Mark it now to avoid re-delivering it on overlapping polls, but drop it
// again if the exchange fails so it can be retried on a subsequent poll.
processedVectorIds.add(vectorId);

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.

Non-blocking / follow-up: processedVectorIds is a plain HashSet, now written from both poll() (scheduler thread) and VectorDedupSynchronization.onFailure() (exchange completion thread — potentially different with async routing). For most configurations this is fine (synchronous routing), but a ConcurrentHashMap.newKeySet() would be safer against subtle races.

Also, when deleteAfterRead=false the set grows unboundedly until doStop(). Both are pre-existing design concerns (not introduced by this PR), but worth a follow-up.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-aws/camel-aws2-s3-vectors

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

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

⚠️ Modules only in Scalpel (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • 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 9 modules (1 direct + 8 downstream), skip tests for 29 (generated code, meta-modules)

Modules Scalpel would test (9)
  • camel-aws2-s3-vectors
  • 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
Modules with tests skipped (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • 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

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

All tested modules (38 modules)
  • Camel :: AWS2 S3 Vectors
  • Camel :: All Components Sync point
  • Camel :: Assembly
  • Camel :: Catalog :: CSimple Maven Plugin (deprecated)
  • Camel :: Catalog :: Camel Catalog
  • Camel :: Catalog :: Camel Report Maven Plugin
  • Camel :: Catalog :: Camel Route Parser
  • Camel :: Catalog :: Console
  • Camel :: Catalog :: Dummy Component
  • Camel :: Catalog :: Lucene (deprecated)
  • Camel :: Catalog :: Maven
  • Camel :: Catalog :: Suggest
  • Camel :: Component DSL
  • Camel :: Coverage
  • Camel :: Docs
  • Camel :: Endpoint DSL
  • Camel :: Endpoint DSL :: Support
  • Camel :: Integration Tests
  • Camel :: JBang :: Core
  • Camel :: JBang :: Integration tests
  • Camel :: JBang :: MCP
  • Camel :: JBang :: Main
  • Camel :: JBang :: Plugin :: Edit
  • Camel :: JBang :: Plugin :: Generate
  • Camel :: JBang :: Plugin :: Kubernetes
  • Camel :: JBang :: Plugin :: MCP
  • Camel :: JBang :: Plugin :: Route Parser
  • Camel :: JBang :: Plugin :: TUI
  • Camel :: JBang :: Plugin :: Testing
  • Camel :: JBang :: Plugin :: Validate
  • Camel :: Kamelet Main
  • Camel :: Launcher
  • Camel :: Launcher :: Container
  • Camel :: YAML DSL
  • Camel :: YAML DSL :: Deserializers
  • Camel :: YAML DSL :: Maven Plugins
  • Camel :: YAML DSL :: Validator
  • Camel :: YAML DSL :: Validator Maven Plugin

⚙️ View full build and test results

davsclaus pushed a commit that referenced this pull request Aug 6, 2026
…ctor loss

Backport of #25369 to camel-4.18.x. The consumer now wires
maxMessagesPerPoll so topK is valid (>= 1), propagates the delay option
to the scheduler, and only marks a vector processed on success so failed
exchanges can be retried.

Closes #25377

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@davsclaus
davsclaus merged commit 43cd5f0 into apache:main Aug 6, 2026
5 checks passed
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 components-aws

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants