Skip to content

Conversation

@gnodet
Copy link
Contributor

@gnodet gnodet commented Feb 2, 2026

Description

Fixes memory leak in Google PubSub consumer when subscription doesn't exist.

Problem

When a subscription no longer exists, starting a subscriber throws a NotFoundException. However, the subscriber was being added to the subscribers list BEFORE the startAsync().awaitRunning() call. This caused subscribers to accumulate in the list on repeated failures, leading to unbounded memory growth until JVM runs out of memory.

Additionally, there was no backoff delay, causing a tight loop that consumed CPU resources.

Solution

This fix addresses the issue in both GooglePubsubConsumer and GooglePubsubLiteConsumer:

  1. Reordered subscriber list management: Subscribers are now added to the list AFTER successful startup
  2. Added proper cleanup: Subscribers are removed from the list in the catch block if startup fails
  3. Added backoff delay: 5-second delay on failures to prevent tight loop
  4. Ensured cleanup in finally block: Subscribers are removed from the list to prevent leaks

Testing

  • ✅ Compiled both components successfully
  • ✅ All existing tests pass (camel-google-pubsub: 4 tests, camel-google-pubsub-lite: 6 tests)
  • ✅ No breaking changes to existing functionality

Related Issue

https://issues.apache.org/jira/browse/CAMEL-22898


Pull Request opened by Augment Code with guidance from the PR author

@github-actions
Copy link
Contributor

github-actions bot commented Feb 2, 2026

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

  • You can label PRs using build-all, build-dependents, 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.

When a subscription doesn't exist, the subscriber.startAsync().awaitRunning()
call throws a NotFoundException. However, the subscriber was being added to
the subscribers list BEFORE this call, causing it to accumulate in the list
on repeated failures.

This fix:
1. Moves the subscribers.add() call to AFTER successful startup
2. Adds proper cleanup in catch block to remove subscribers on failure
3. Adds a 5-second backoff delay to prevent tight loop on persistent failures
4. Ensures cleanup in finally block

Applied to both GooglePubsubConsumer and GooglePubsubLiteConsumer.
@gnodet gnodet force-pushed the CAMEL-22898-fix-pubsub-memory-leak branch from b79c7bd to f7efc21 Compare February 2, 2026 08:58
…rors

Enhanced error handling to distinguish between recoverable and non-recoverable
errors using ApiException.isRetryable():

- Recoverable errors (e.g., ABORTED, UNAVAILABLE, UNKNOWN): Continue retrying
  with 5-second backoff delay
- Non-recoverable errors (e.g., NotFoundException, permission errors): Exit the
  subscriber loop immediately without retrying

This prevents infinite retry loops for errors that cannot be recovered, while
still allowing automatic recovery from transient failures.

Applied to both GooglePubsubConsumer and GooglePubsubLiteConsumer.
@gnodet gnodet marked this pull request as draft February 2, 2026 09:07
… delays

Replaced Thread.sleep() with Tasks.foregroundTask() using IterationBudget
to implement the 5-second backoff delay for recoverable errors. This
integrates better with Camel's task management framework.

Applied to both GooglePubsubConsumer and GooglePubsubLiteConsumer.
@gnodet gnodet force-pushed the CAMEL-22898-fix-pubsub-memory-leak branch from 2c35419 to 9fda7c8 Compare February 2, 2026 09:30
The ForegroundTask only sleeps between iterations, not before the first iteration.
For a one-time delay with maxIterations(1), we must use withInitialDelay() to ensure
the delay happens before the first iteration.

This fixes the backoff delay in both GooglePubsubConsumer and GooglePubsubLiteConsumer.
Resolved conflict in GooglePubsubConsumer.java by keeping both the new
UnitOfWorkHelper import from main and our Task API imports.
@gnodet gnodet marked this pull request as ready for review February 2, 2026 13:07
@gnodet gnodet merged commit 2fad26a into apache:main Feb 2, 2026
4 checks passed
@gnodet gnodet deleted the CAMEL-22898-fix-pubsub-memory-leak branch February 2, 2026 13:10
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.

4 participants