-
Feature
-
Resolution: Unresolved
-
Major
-
None
-
4.14.GA
-
None
-
False
-
-
False
-
Subscription example configuration:
gcloud pubsub subscriptions create publisher-subscription \ --topic=publisher-topic \ --ack-deadline=10 \ --dead-letter-topic=publisher-topic-dlq \ --max-delivery-attempts=5 \ --min-retry-delay=5s \ --max-retry-delay=15s
The camel-google-pubsub component does not expose or act upon the subscription-level maxDeliveryAttempts setting from the dead-letter policy. When a subscription is configured with a short retry window (--min-retry-delay=5s, --max-retry-delay=15s), the consumer enters an infinite redelivery loop because it has no mechanism to compare the current delivery attempt against the configured maximum. The component should be able to avoid this infinite loop when using a low window delays.
Increasing --min-retry-delay to 30s and --max-retry-delay to 60s alleviates the symptom but does not address the root cause, the component lacks delivery attempt control.
In general the library should retrieve the maxDeliveryAttempts from the subscription dead-letter policy at startup, expose the current delivery attempt and optionally enforce the max delivery control, when the current attempt reaches maxDeliveryAttempts, the component could automatically NACK the message (allowing Pub/Sub to route it to the DLQ) instead of continuing to process it.
WORKAROUND:
//Add these imports import com.google.cloud.pubsub.v1.SubscriptionAdminClient; import com.google.pubsub.v1.DeadLetterPolicy; import com.google.pubsub.v1.Subscription; import com.google.pubsub.v1.SubscriptionName; ... public class PubSubRoute extends RouteBuilder { ... @Override public void configure() throws Exception { ... try (SubscriptionAdminClient client = SubscriptionAdminClient.create()) { SubscriptionName subName = SubscriptionName.of(projectId, subscriptionId); Subscription sub = client.getSubscription(subName); DeadLetterPolicy dlp = sub.getDeadLetterPolicy(); int maxAttempts = dlp.getMaxDeliveryAttempts(); log.info("maxDeliveryAttempts={}", maxAttempts); } ...
The above will capture the property correctly:
2026-03-04 10:55:47,750 INFO [demo.PubSubRoute] (Quarkus Main Thread) maxDeliveryAttempts=5
Then you can capture the current attempt:
... Object rawAttrs = exchange.getIn().getHeader(GooglePubsubConstants.ATTRIBUTES); Map<String, String> attrs = new HashMap<>(); if (rawAttrs instanceof Map<?, ?> map) { for (Map.Entry<?, ?> e : map.entrySet()) { if (e.getKey() instanceof String && e.getValue() instanceof String) { attrs.put((String) e.getKey(), (String) e.getValue()); } } } int attempt = Integer.parseInt( attrs.getOrDefault("googclient_deliveryattempt", "1") ); ...
And apply the max delivery control in your camel solution.
if (attempt >= maxAttempts) { thrownewRuntimeException("Max delivery attempts exceeded"); }