Conversation
…a geo-replicator GeoPersistentReplicator.getLocalPartitionMetadata() handles a 404 from the local partitioned-metadata lookup by looking the topic up again as a legacy non-partitioned topic named "-partition-N". That fallback took the same branch again on every further 404, so while the local topic stayed missing (e.g. it was deleted while the replicator was starting) the lookups were repeated forever without any backoff, the prepareCreateProducer() future never completed, and startProducer() never reached its backoff/retry handling. Take the fallback only when the failed lookup was not already for the local topic name, so that it runs at most once and a second 404 fails the future. Assisted-by: Claude Code (Fable 5.1)
void-ptr974
approved these changes
Sep 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
GeoPersistentReplicator.getLocalPartitionMetadata()asks the local admin API for the partitioned metadata of the topic being replicated. When that lookup returns 404, it takes the "legacy edge case" branch (a non-partitioned topic whose name ends in-partition-N, from PIP-433) and callscreateRemoteTopicIfDoesNotExist(localTopicName), which performs the same local lookup again. That fallback is unconditional, so as long as the local lookup keeps returning 404 the replicator loops forever: no backoff, one new admin request per iteration, and theprepareCreateProducer()future never completes.AbstractReplicator.startProducer()therefore never reaches itsexceptionally(...)retry/backoff path and the replicator is stuck inStarting.For a regular (non-partitioned) topic,
TopicName.getPartitionedTopicName()is the topic's own name, so the "fallback" repeats the identical request. The lookup returns 404 persistently when the local topic is deleted (or its namespace is deleted) while the replicator is starting, and nothing in the loop checks the replicator state.Reproduced on two real brokers by creating a regular topic, deleting it, and calling the replicator's prepare step: on the unpatched code the future was still pending after 5 seconds, during which the local broker had answered 5,487
GET .../partitionsrequests with 404 (about 1,100 per second), while the replicator itself was alreadyTerminated. The loop keeps going until the broker is restarted. The same loop was also triggered bysegment://topics, whose/partitionsREST path does not exist; that trigger is being removed separately, but the recursion itself is unbounded by construction.Modifications
GeoPersistentReplicator.getLocalPartitionMetadata(): take the legacy fallback only when the failed lookup was not already forlocalTopicName. The fallback always passeslocalTopicName, so it now runs at most once and a second 404 fails the returned future with theNotFoundException, letting the existing backoff instartProducer()handle the retry. The legacy behaviour for a non-partitioned topic named-partition-Nis unchanged.GeoPersistentReplicatorPrepareCreateProducerTest(mocks only,broker-replicationgroup). The mocked admin futures are completed from another thread, like the real admin client does, so that the unpatched code hangs instead of overflowing the stack.With the fix, the real-broker reproduction above fails in 4 ms after a single local lookup.
Verifying this change
This change added tests and can be verified as follows:
GeoPersistentReplicatorPrepareCreateProducerTest.testLocalTopicNotFoundFailsPreparation: with the local lookup always answering 404, the prepare future fails withNotFoundExceptionand the local admin is queried exactly once for a regular topic and exactly twice (base name, then the-partition-0name) for a legacy name; the remote cluster is never contacted. Both rows time out on the unpatched code because the future never completes.GeoPersistentReplicatorPrepareCreateProducerTest.testLegacyNonPartitionedTopicWithPartitionSuffix: the legacy fallback still creates the-partition-0topic on the remote cluster as a non-partitioned topic (passes before and after the fix).OneWayReplicatorTest.testReplicatorCreateTopic,testReplicatorCreateTopicWhenTopicExistsWithDifferentTypeAcrossClusters,testReplicatorWhenPartitionCountsDiffer,AbstractReplicatorTest,PersistentTopicTest.testClosingReplicationProducerTwice/testAtomicReplicationRemoval,GeoShadowReplicatorUnsentEntryCleanupTest.Does this pull request potentially affect one of the following parts:
If the box was checked, please highlight the changes